From db460762c2da8f2cb49195094f7c07f7ee3f3ed7 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Mon, 16 Oct 2023 14:32:31 -0400 Subject: [PATCH 001/133] add fingerprinting template (#30257) Add fingerprint template --- .github/pull_request_template.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index efa947a91a83d6f..6fbccfbdbb73835 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,5 +1,15 @@ + + @@ -93,6 +62,71 @@ VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) { timeline_colors[(int)TimelineType::AlertCritical].name())); } +QHBoxLayout *VideoWidget::createPlaybackController() { + QHBoxLayout *layout = new QHBoxLayout(); + layout->addWidget(seek_backward_btn = new ToolButton("rewind", tr("Seek backward"))); + layout->addWidget(play_btn = new ToolButton("play", tr("Play"))); + layout->addWidget(seek_forward_btn = new ToolButton("fast-forward", tr("Seek forward"))); + + if (can->liveStreaming()) { + layout->addWidget(skip_to_end_btn = new ToolButton("skip-end", tr("Skip to the end"), this)); + QObject::connect(skip_to_end_btn, &QToolButton::clicked, [this]() { + // set speed to 1.0 + speed_btn->menu()->actions()[7]->setChecked(true); + can->pause(false); + can->seekTo(can->totalSeconds() + 1); + }); + } + + layout->addWidget(time_btn = new QToolButton); + time_btn->setToolTip(settings.absolute_time ? tr("Elapsed time") : tr("Absolute time")); + time_btn->setAutoRaise(true); + layout->addStretch(0); + + if (!can->liveStreaming()) { + layout->addWidget(loop_btn = new ToolButton("repeat", tr("Loop playback"))); + QObject::connect(loop_btn, &QToolButton::clicked, this, &VideoWidget::loopPlaybackClicked); + } + + // speed selector + layout->addWidget(speed_btn = new QToolButton(this)); + speed_btn->setAutoRaise(true); + speed_btn->setMenu(new QMenu(speed_btn)); + speed_btn->setPopupMode(QToolButton::InstantPopup); + QActionGroup *speed_group = new QActionGroup(this); + speed_group->setExclusive(true); + + int max_width = 0; + QFont font = speed_btn->font(); + font.setBold(true); + speed_btn->setFont(font); + QFontMetrics fm(font); + for (float speed : {0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 0.8, 1., 2., 3., 5.}) { + QString name = QString("%1x").arg(speed); + max_width = std::max(max_width, fm.width(name) + fm.horizontalAdvance(QLatin1Char(' ')) * 2); + + QAction *act = new QAction(name, speed_group); + act->setCheckable(true); + QObject::connect(act, &QAction::toggled, [this, speed]() { + can->setSpeed(speed); + speed_btn->setText(QString("%1x ").arg(speed)); + }); + speed_btn->menu()->addAction(act); + if (speed == 1.0)act->setChecked(true); + } + speed_btn->setMinimumWidth(max_width + style()->pixelMetric(QStyle::PM_MenuButtonIndicator)); + + QObject::connect(play_btn, &QToolButton::clicked, []() { can->pause(!can->isPaused()); }); + QObject::connect(seek_backward_btn, &QToolButton::clicked, []() { can->seekTo(can->currentSec() - 1); }); + QObject::connect(seek_forward_btn, &QToolButton::clicked, []() { can->seekTo(can->currentSec() + 1); }); + QObject::connect(time_btn, &QToolButton::clicked, [this]() { + settings.absolute_time = !settings.absolute_time; + time_btn->setToolTip(settings.absolute_time ? tr("Elapsed time") : tr("Absolute time")); + updateState(); + }); + return layout; +} + QWidget *VideoWidget::createCameraWidget() { QWidget *w = new QWidget(this); QVBoxLayout *l = new QVBoxLayout(w); @@ -106,30 +140,30 @@ QWidget *VideoWidget::createCameraWidget() { stacked->addWidget(alert_label = new InfoLabel(this)); l->addLayout(stacked); - // slider controls - auto slider_layout = new QHBoxLayout(); - slider_layout->addWidget(time_label = new QLabel("00:00")); - - slider = new Slider(this); + l->addWidget(slider = new Slider(this)); slider->setSingleStep(0); - slider_layout->addWidget(slider); - - slider_layout->addWidget(end_time_label = new QLabel(this)); - l->addLayout(slider_layout); setMaximumTime(can->totalSeconds()); QObject::connect(slider, &QSlider::sliderReleased, [this]() { can->seekTo(slider->currentSecond()); }); - QObject::connect(slider, &QSlider::valueChanged, [=](int value) { time_label->setText(utils::formatSeconds(slider->currentSecond())); }); QObject::connect(slider, &Slider::updateMaximumTime, this, &VideoWidget::setMaximumTime, Qt::QueuedConnection); QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); QObject::connect(static_cast(can), &ReplayStream::qLogLoaded, slider, &Slider::parseQLog); - QObject::connect(can, &AbstractStream::updated, this, &VideoWidget::updateState); return w; } +void VideoWidget::loopPlaybackClicked() { + auto replay = qobject_cast(can)->getReplay(); + if (replay->hasFlag(REPLAY_FLAG_NO_LOOP)) { + replay->removeFlag(REPLAY_FLAG_NO_LOOP); + loop_btn->setIcon("repeat"); + } else { + replay->addFlag(REPLAY_FLAG_NO_LOOP); + loop_btn->setIcon("repeat-1"); + } +} + void VideoWidget::setMaximumTime(double sec) { maximum_time = sec; - end_time_label->setText(utils::formatSeconds(sec)); slider->setTimeRange(0, sec); } @@ -143,19 +177,29 @@ void VideoWidget::updateTimeRange(double min, double max, bool is_zoomed) { min = 0; max = maximum_time; } - end_time_label->setText(utils::formatSeconds(max)); slider->setTimeRange(min, max); } +QString VideoWidget::formatTime(double sec, bool include_milliseconds) { + if (settings.absolute_time) + sec = can->beginDateTime().addMSecs(sec * 1000).toMSecsSinceEpoch() / 1000.0; + return utils::formatSeconds(sec, include_milliseconds, settings.absolute_time); +} + void VideoWidget::updateState() { - if (!slider->isSliderDown()) { - slider->setCurrentSecond(can->currentSec()); + if (slider) { + if (!slider->isSliderDown()) + slider->setCurrentSecond(can->currentSec()); + alert_label->showAlert(slider->alertInfo(can->currentSec())); + time_btn->setText(QString("%1 / %2").arg(formatTime(can->currentSec(), true), + formatTime(slider->maximum() / slider->factor))); + } else { + time_btn->setText(formatTime(can->currentSec(), true)); } - alert_label->showAlert(slider->alertInfo(can->currentSec())); } void VideoWidget::updatePlayBtnState() { - play_btn->setIcon(utils::icon(can->isPaused() ? "play" : "pause")); + play_btn->setIcon(can->isPaused() ? "play" : "pause"); play_btn->setToolTip(can->isPaused() ? tr("Play") : tr("Pause")); } @@ -284,8 +328,7 @@ void InfoLabel::showPixmap(const QPoint &pt, const QString &sec, const QPixmap & second = sec; pixmap = pm; alert_info = alert; - resize(pm.size()); - move(pt); + setGeometry(QRect(pt, pm.size())); setVisible(true); update(); } diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 12961cd0615d937..68e046111739653 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include @@ -39,6 +39,8 @@ class Slider : public QSlider { QPixmap thumbnail(double sec); void parseQLog(int segnum, std::shared_ptr qlog); + const double factor = 1000.0; + signals: void updateMaximumTime(double); @@ -48,7 +50,6 @@ class Slider : public QSlider { bool event(QEvent *event) override; void paintEvent(QPaintEvent *ev) override; - const double factor = 1000.0; QMap thumbnails; std::map alerts; InfoLabel thumbnail_label; @@ -63,16 +64,22 @@ class VideoWidget : public QFrame { void setMaximumTime(double sec); protected: + QString formatTime(double sec, bool include_milliseconds = false); void updateState(); void updatePlayBtnState(); QWidget *createCameraWidget(); + QHBoxLayout *createPlaybackController(); + void loopPlaybackClicked(); CameraWidget *cam_widget; double maximum_time = 0; - QLabel *end_time_label; - QLabel *time_label; - QToolButton *play_btn; - QToolButton *skip_to_end_btn = nullptr; - InfoLabel *alert_label; - Slider *slider; + QToolButton *time_btn = nullptr; + ToolButton *seek_backward_btn = nullptr; + ToolButton *play_btn = nullptr; + ToolButton *seek_forward_btn = nullptr; + ToolButton *loop_btn = nullptr; + QToolButton *speed_btn = nullptr; + ToolButton *skip_to_end_btn = nullptr; + InfoLabel *alert_label = nullptr; + Slider *slider = nullptr; }; From b73329092c1eeb9b7472db97fcdf5544ee848156 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 26 Oct 2023 05:39:41 +0800 Subject: [PATCH 050/133] cabana: save settings to user-specific directory (#30328) * save settings to user-specific directory * include --- tools/cabana/.gitignore | 1 - tools/cabana/cabana.cc | 2 - tools/cabana/mainwin.cc | 6 -- tools/cabana/messageswidget.cc | 1 + tools/cabana/settings.cc | 128 +++++++++++----------------- tools/cabana/settings.h | 13 +-- tools/cabana/streams/pandastream.cc | 1 + tools/cabana/tools/findsignal.h | 1 + 8 files changed, 55 insertions(+), 98 deletions(-) diff --git a/tools/cabana/.gitignore b/tools/cabana/.gitignore index c3f5ef2b69fbdab..362a51f5c9231de 100644 --- a/tools/cabana/.gitignore +++ b/tools/cabana/.gitignore @@ -2,6 +2,5 @@ moc_* *.moc cabana -settings dbc/car_fingerprint_to_dbc.json tests/test_cabana diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index 0ccef7d3aba8453..33403a2bff9ccdf 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -18,8 +18,6 @@ int main(int argc, char *argv[]) { app.setWindowIcon(QIcon(":cabana-icon.png")); UnixSignalHandler signalHandler; - - settings.load(); utils::setTheme(settings.theme); QCommandLineParser cmd_parser; diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 9ac88032d5ed30d..4f27dcf5ed30fb0 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -608,12 +608,6 @@ void MainWindow::closeEvent(QCloseEvent *event) { } settings.message_header_state = messages_widget->saveHeaderState(); - auto status = settings.save(); - if (status == QSettings::AccessError) { - QString error = tr("Failed to write settings to [%1]: access denied").arg(Settings::filePath()); - qDebug() << error; - QMessageBox::warning(this, tr("Failed to write settings"), error); - } QWidget::closeEvent(event); } diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 6a94e013f684227..aea09c55dee1523 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -2,6 +2,7 @@ #include +#include #include #include #include diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index c408179fddfd5b1..ac8d45007d65a27 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -6,65 +6,51 @@ #include #include #include +#include #include +#include #include "tools/cabana/util.h" Settings settings; -QSettings::Status Settings::save() { - QSettings s(filePath(), QSettings::IniFormat); - s.setValue("absolute_time", absolute_time); - s.setValue("fps", fps); - s.setValue("max_cached_minutes", max_cached_minutes); - s.setValue("chart_height", chart_height); - 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); - s.setValue("recent_files", recent_files); - s.setValue("message_header_state_v3", message_header_state); - s.setValue("chart_series_type", chart_series_type); - s.setValue("theme", theme); - s.setValue("sparkline_range", sparkline_range); - s.setValue("multiple_lines_bytes", multiple_lines_bytes); - s.setValue("log_livestream", log_livestream); - s.setValue("log_path", log_path); - s.setValue("drag_direction", drag_direction); - s.setValue("suppress_defined_signals", suppress_defined_signals); - s.sync(); - return s.status(); +template +void settings_op(SettingOperation op) { + QSettings s("cabana"); + op(s, "absolute_time", settings.absolute_time); + op(s, "fps", settings.fps); + op(s, "max_cached_minutes", settings.max_cached_minutes); + op(s, "chart_height", settings.chart_height); + op(s, "chart_range", settings.chart_range); + op(s, "chart_column_count", settings.chart_column_count); + op(s, "last_dir", settings.last_dir); + op(s, "last_route_dir", settings.last_route_dir); + op(s, "window_state", settings.window_state); + op(s, "geometry", settings.geometry); + op(s, "video_splitter_state", settings.video_splitter_state); + op(s, "recent_files", settings.recent_files); + op(s, "message_header_state", settings.message_header_state); + op(s, "chart_series_type", settings.chart_series_type); + op(s, "theme", settings.theme); + op(s, "sparkline_range", settings.sparkline_range); + op(s, "multiple_lines_bytes", settings.multiple_lines_bytes); + op(s, "log_livestream", settings.log_livestream); + op(s, "log_path", settings.log_path); + op(s, "drag_direction", (int &)settings.drag_direction); + op(s, "suppress_defined_signals", settings.suppress_defined_signals); } -void Settings::load() { - QSettings s(filePath(), QSettings::IniFormat); - absolute_time = s.value("absolute_time", false).toBool(); - fps = s.value("fps", 10).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(); - 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(); - recent_files = s.value("recent_files").toStringList(); - message_header_state = s.value("message_header_state_v3").toByteArray(); - chart_series_type = s.value("chart_series_type", 0).toInt(); - theme = s.value("theme", 0).toInt(); - sparkline_range = s.value("sparkline_range", 15).toInt(); - multiple_lines_bytes = s.value("multiple_lines_bytes", true).toBool(); - log_livestream = s.value("log_livestream", true).toBool(); - log_path = s.value("log_path").toString(); - drag_direction = (Settings::DragDirection)s.value("drag_direction", 0).toInt(); - suppress_defined_signals = s.value("suppress_defined_signals", false).toBool(); - if (log_path.isEmpty()) { - log_path = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/cabana_live_stream/"; - } +Settings::Settings() { + last_dir = last_route_dir = QDir::homePath(); + log_path = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/cabana_live_stream/"; + settings_op([](QSettings &s, const QString &key, auto &value) { + if (auto v = s.value(key); v.canConvert>()) + value = v.value>(); + }); +} + +Settings::~Settings() { + settings_op([](QSettings &s, const QString &key, auto &v) { s.setValue(key, v); }); } // SettingsDlg @@ -75,45 +61,39 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { QGroupBox *groupbox = new QGroupBox("General"); QFormLayout *form_layout = new QFormLayout(groupbox); - theme = new QComboBox(this); + form_layout->addRow(tr("Color Theme"), theme = new QComboBox(this)); theme->setToolTip(tr("You may need to restart cabana after changes theme")); theme->addItems({tr("Automatic"), tr("Light"), tr("Dark")}); theme->setCurrentIndex(settings.theme); - form_layout->addRow(tr("Color Theme"), theme); - fps = new QSpinBox(this); + form_layout->addRow("FPS", fps = new QSpinBox(this)); fps->setRange(10, 100); fps->setSingleStep(10); fps->setValue(settings.fps); - form_layout->addRow("FPS", fps); - cached_minutes = new QSpinBox(this); + form_layout->addRow(tr("Max Cached Minutes"), 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); main_layout->addWidget(groupbox); groupbox = new QGroupBox("New Signal Settings"); form_layout = new QFormLayout(groupbox); - drag_direction = new QComboBox(this); + form_layout->addRow(tr("Drag Direction"), drag_direction = new QComboBox(this)); drag_direction->addItems({tr("MSB First"), tr("LSB First"), tr("Always Little Endian"), tr("Always Big Endian")}); drag_direction->setCurrentIndex(settings.drag_direction); - form_layout->addRow(tr("Drag Direction"), drag_direction); main_layout->addWidget(groupbox); groupbox = new QGroupBox("Chart"); form_layout = new QFormLayout(groupbox); - chart_series_type = new QComboBox(this); + form_layout->addRow(tr("Default Series Type"), chart_series_type = new QComboBox(this)); 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); - chart_height = new QSpinBox(this); + form_layout->addRow(tr("Chart Height"), 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->addWidget(groupbox); log_livestream = new QGroupBox(tr("Enable live stream logging"), this); @@ -125,10 +105,9 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { path_layout->addWidget(browse_btn); main_layout->addWidget(log_livestream); - - auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Apply); + auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); main_layout->addWidget(buttonBox); - main_layout->addStretch(1); + setFixedSize(400, sizeHint().height()); QObject::connect(browse_btn, &QPushButton::clicked, [this]() { QString fn = QFileDialog::getExistingDirectory( @@ -139,31 +118,22 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { log_path->setText(fn); } }); - QObject::connect(buttonBox, &QDialogButtonBox::clicked, [=](QAbstractButton *button) { - auto role = buttonBox->buttonRole(button); - if (role == QDialogButtonBox::AcceptRole) { - save(); - accept(); - } else if (role == QDialogButtonBox::ApplyRole) { - save(); - } else if (role == QDialogButtonBox::RejectRole) { - reject(); - } - }); + QObject::connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &SettingsDlg::save); } void SettingsDlg::save() { - settings.fps = fps->value(); if (std::exchange(settings.theme, theme->currentIndex()) != settings.theme) { // set theme before emit changed utils::setTheme(settings.theme); } + 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.log_livestream = log_livestream->isChecked(); settings.log_path = log_path->text(); settings.drag_direction = (Settings::DragDirection)drag_direction->currentIndex(); - settings.save(); emit settings.changed(); + QDialog::accept(); } diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index da7781e6e44e869..9f24a6fbd370f78 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -1,13 +1,10 @@ #pragma once -#include #include -#include #include #include #include #include -#include #include #define LIGHT_THEME 1 @@ -24,10 +21,8 @@ class Settings : public QObject { AlwaysBE, }; - Settings() {} - QSettings::Status save(); - void load(); - inline static QString filePath() { return QApplication::applicationDirPath() + "/settings"; } + Settings(); + ~Settings(); bool absolute_time = false; int fps = 10; @@ -49,15 +44,13 @@ class Settings : public QObject { QByteArray window_state; QStringList recent_files; QByteArray message_header_state; - DragDirection drag_direction; + DragDirection drag_direction = MsbFirst; signals: void changed(); }; class SettingsDlg : public QDialog { - Q_OBJECT - public: SettingsDlg(QWidget *parent); void save(); diff --git a/tools/cabana/streams/pandastream.cc b/tools/cabana/streams/pandastream.cc index 4a6c588e5102eb6..13d202d9cab3200 100644 --- a/tools/cabana/streams/pandastream.cc +++ b/tools/cabana/streams/pandastream.cc @@ -2,6 +2,7 @@ #include +#include #include #include #include diff --git a/tools/cabana/tools/findsignal.h b/tools/cabana/tools/findsignal.h index e9e5f9f1808895a..5ef7461fee276bc 100644 --- a/tools/cabana/tools/findsignal.h +++ b/tools/cabana/tools/findsignal.h @@ -4,6 +4,7 @@ #include #include +#include #include #include #include From ae2628011818d3bb4277890e33e2a3917ba97f40 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 26 Oct 2023 05:39:52 +0800 Subject: [PATCH 051/133] cabana: fix two ui bugs (#30327) fix ui bugs --- tools/cabana/signalview.cc | 7 ++++--- tools/cabana/videowidget.cc | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 934609a439ef46a..70f09e7419ee677 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -504,7 +504,7 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), QObject::connect(can, &AbstractStream::msgsReceived, this, &SignalView::updateState); QObject::connect(tree->header(), &QHeaderView::sectionResized, [this](int logicalIndex, int oldSize, int newSize) { if (logicalIndex == 1) { - value_column_width = newSize - delegate->button_size.width(); + value_column_width = newSize; updateState(); } }); @@ -645,8 +645,9 @@ void SignalView::updateState(const QHash *msgs) { } const static int min_max_width = QFontMetrics(delegate->minmax_font).width("-000.00") + 5; - int value_width = std::min(max_value_width + min_max_width, value_column_width / 2); - QSize size(value_column_width - value_width, + int available_width = value_column_width - delegate->button_size.width(); + int value_width = std::min(max_value_width + min_max_width, available_width / 2); + QSize size(available_width - value_width, delegate->button_size.height() - style()->pixelMetric(QStyle::PM_FocusFrameVMargin) * 2); QFutureSynchronizer synchronizer; for (int i = first_visible_row; i <= last_visible_row; ++i) { diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 0a1d2855a560296..f7f566507ceff2b 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -140,7 +140,7 @@ QWidget *VideoWidget::createCameraWidget() { stacked->addWidget(alert_label = new InfoLabel(this)); l->addLayout(stacked); - l->addWidget(slider = new Slider(this)); + l->addWidget(slider = new Slider(w)); slider->setSingleStep(0); setMaximumTime(can->totalSeconds()); @@ -293,9 +293,9 @@ void Slider::mouseMoveEvent(QMouseEvent *e) { double seconds = (minimum() + pos * ((maximum() - minimum()) / (double)width())) / factor; QPixmap thumb = thumbnail(seconds); if (!thumb.isNull()) { - int x = std::clamp(pos - thumb.width() / 2, THUMBNAIL_MARGIN, rect().right() - thumb.width() - THUMBNAIL_MARGIN); - int y = -thumb.height(); - thumbnail_label.showPixmap(mapToParent({x, y}), utils::formatSeconds(seconds), thumb, alertInfo(seconds)); + int x = std::clamp(pos - thumb.width() / 2, THUMBNAIL_MARGIN, width() - thumb.width() - THUMBNAIL_MARGIN + 1); + int y = -thumb.height() - THUMBNAIL_MARGIN - 6; + thumbnail_label.showPixmap(mapToParent(QPoint(x, y)), utils::formatSeconds(seconds), thumb, alertInfo(seconds)); } else { thumbnail_label.hide(); } From 82291a247f13b592d5cc1ec0b25385619b283586 Mon Sep 17 00:00:00 2001 From: Madnevil Date: Wed, 25 Oct 2023 23:57:08 +0200 Subject: [PATCH 052/133] Honda: add FW for Civic Sport 2023 (#30316) * Update values.py * Update values.py * Update values.py * removing duplicate * Update values.py * Update values.py * this is from a logging request * Add missing FW * bump MY --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 4 ++-- selfdrive/car/honda/values.py | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index d6961f6f56b3953..c720e93fd94e127 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -55,9 +55,9 @@ A supported vehicle is one that just works when you install a comma device. All |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)](##)|
Parts- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[5](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Civic 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Civic 2022-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |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)](##)|
Parts- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Honda|Civic Hatchback 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Honda|Civic Hatchback 2022-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |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)](##)|
Parts- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |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)](##)|
Parts- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 092231d60cd246a..38ba0f22fe919cc 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -129,8 +129,8 @@ def init_make(self, CP: car.CarParams): ], CAR.CIVIC_BOSCH_DIESEL: None, # same platform CAR.CIVIC_2022: [ - HondaCarInfo("Honda Civic 2022", "All", video_link="https://youtu.be/ytiOT5lcp6Q"), - HondaCarInfo("Honda Civic Hatchback 2022", "All", video_link="https://youtu.be/ytiOT5lcp6Q"), + HondaCarInfo("Honda Civic 2022-23", "All", video_link="https://youtu.be/ytiOT5lcp6Q"), + HondaCarInfo("Honda Civic Hatchback 2022-23", "All", video_link="https://youtu.be/ytiOT5lcp6Q"), ], 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), @@ -1519,6 +1519,7 @@ def init_make(self, CP: car.CarParams): b'77959-T47-A940\x00\x00', b'77959-T47-A950\x00\x00', b'77959-T20-M820\x00\x00', + b'77959-T20-A980\x00\x00', ], (Ecu.combinationMeter, 0x18DA60F1, None): [ b'78108-T21-A220\x00\x00', @@ -1527,6 +1528,7 @@ def init_make(self, CP: car.CarParams): b'78108-T21-A230\x00\x00', b'78108-T22-A020\x00\x00', b'78108-T21-MB10\x00\x00', + b'78108-T21-A740\x00\x00', ], (Ecu.fwdRadar, 0x18dab0f1, None): [ b'36161-T20-A070\x00\x00', @@ -1554,6 +1556,7 @@ def init_make(self, CP: car.CarParams): b'37805-64A-A540\x00\x00', b'37805-64A-A620\x00\x00', b'37805-64D-P510\x00\x00', + b'37805-64S-AA10\x00\x00', ], }, } From f62ee97cb0d05f71873f768145ccc122c1c82884 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 25 Oct 2023 15:03:27 -0700 Subject: [PATCH 053/133] cabana: rename signal node More clear what this is Receiver Nodes --- tools/cabana/signalview.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 70f09e7419ee677..b9795efedfa71b5 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -36,7 +36,7 @@ SignalModel::SignalModel(QObject *parent) : root(new Item), QAbstractItemModel(p 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", "Node", "Little Endian", "Signed", "Offset", "Factor", "Type", "Multiplex Value", "Extra Info", + QString titles[]{"Name", "Size", "Receiver Nodes", "Little Endian", "Signed", "Offset", "Factor", "Type", "Multiplex Value", "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)}); From 9c7e5ca6eaf3672828785ed70dfd10daaba46397 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 25 Oct 2023 15:05:07 -0700 Subject: [PATCH 054/133] rawgpsd: add flag for cold start (#30224) * rawgpsd: add flag for cold start * other datasheet is wrong * keep things in a good state --- system/sensord/rawgps/rawgpsd.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/system/sensord/rawgps/rawgpsd.py b/system/sensord/rawgps/rawgpsd.py index e710a16920500ee..b947c548720bb57 100755 --- a/system/sensord/rawgps/rawgpsd.py +++ b/system/sensord/rawgps/rawgpsd.py @@ -190,7 +190,13 @@ def setup_quectel(diag: ModemDiag) -> bool: if gps_enabled(): at_cmd("AT+QGPSEND") - #at_cmd("AT+QGPSDEL=0") + + if "GPS_COLD_START" in os.environ: + # deletes all assistance + at_cmd("AT+QGPSDEL=0") + else: + # allow module to perform hot start + at_cmd("AT+QGPSDEL=1") # disable DPO power savings for more accuracy at_cmd("AT+QGPSCFG=\"dpoenable\",0") From 2acb22fadacaa57919e1bf7bbe93e49542db6600 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 25 Oct 2023 15:17:17 -0700 Subject: [PATCH 055/133] selfdrive_tests: allow manual run (#30307) * allow manual run * Apply suggestions from code review --- .github/workflows/selfdrive_tests.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 7b31173b5cf6b96..bd6885cf5b5c341 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -5,6 +5,7 @@ on: branches: - master pull_request: + workflow_dispatch: concurrency: group: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }} From 21715d7f810aa67213d767829c41ae42541c6b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Wed, 25 Oct 2023 15:42:06 -0700 Subject: [PATCH 056/133] process_replay: migrate cameraStates of segments without driverEncodeIdx (#30331) Migrate camera states of segments without driverEncodeIdx --- selfdrive/test/process_replay/migration.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/selfdrive/test/process_replay/migration.py b/selfdrive/test/process_replay/migration.py index a44567969119d23..ad5192dbba6080c 100644 --- a/selfdrive/test/process_replay/migration.py +++ b/selfdrive/test/process_replay/migration.py @@ -94,6 +94,8 @@ def migrate_peripheralState(lr): def migrate_cameraStates(lr): all_msgs = [] frame_to_encode_id = defaultdict(dict) + # just for encodeId fallback mechanism + min_frame_id = defaultdict(lambda: float('inf')) for msg in lr: if msg.which() not in ["roadEncodeIdx", "wideRoadEncodeIdx", "driverEncodeIdx"]: @@ -111,10 +113,18 @@ def migrate_cameraStates(lr): continue camera_state = getattr(msg, msg.which()) + min_frame_id[msg.which()] = min(min_frame_id[msg.which()], camera_state.frameId) + encode_id = frame_to_encode_id[msg.which()].get(camera_state.frameId) if encode_id is None: print(f"Missing encoded frame for camera feed {msg.which()} with frameId: {camera_state.frameId}") - continue + if len(frame_to_encode_id[msg.which()]) != 0: + continue + + # fallback mechanism for logs without encodeIdx (e.g. logs from before 2022 with dcamera recording disabled) + # try to fake encode_id by subtracting lowest frameId + encode_id = camera_state.frameId - min_frame_id[msg.which()] + print(f"Faking encodeId to {encode_id} for camera feed {msg.which()} with frameId: {camera_state.frameId}") new_msg = messaging.new_message(msg.which()) new_camera_state = getattr(new_msg, new_msg.which()) From 4094d584f3b7788d50eb90110b6f3d7651c96863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Wed, 25 Oct 2023 15:46:16 -0700 Subject: [PATCH 057/133] process_replay: use frame dimensions from FrameReader (#30332) Use dimensions from FrameReader to setup vipc server --- .../test/process_replay/process_replay.py | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 0cb8ac9cac237a1..a520b3d7409e467 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -27,6 +27,7 @@ from openpilot.selfdrive.test.process_replay.migration import migrate_all from openpilot.selfdrive.test.process_replay.capture import ProcessOutputCapture from openpilot.tools.lib.logreader import LogIterable +from openpilot.tools.lib.framereader import BaseFrameReader # Numpy gives different results based on CPU features after version 19 NUMPY_TOLERANCE = 1e-7 @@ -201,16 +202,15 @@ def _setup_env(self, params_config: Dict[str, Any], environ_config: Dict[str, An self.environ_config = environ_config - def _setup_vision_ipc(self, all_msgs): + def _setup_vision_ipc(self, all_msgs: LogIterable, frs: Dict[str, Any]): assert len(self.cfg.vision_pubs) != 0 - device_type = next(str(msg.initData.deviceType) for msg in all_msgs if msg.which() == "initData") - vipc_server = VisionIpcServer("camerad") streams_metas = available_streams(all_msgs) for meta in streams_metas: if meta.camera_state in self.cfg.vision_pubs: - vipc_server.create_buffers(meta.stream, 2, False, *meta.frame_sizes[device_type]) + frame_size = (frs[meta.camera_state].w, frs[meta.camera_state].h) + vipc_server.create_buffers(meta.stream, 2, False, *frame_size) vipc_server.start_listener() self.vipc_server = vipc_server @@ -224,7 +224,7 @@ def _start_process(self): def start( self, params_config: Dict[str, Any], environ_config: Dict[str, Any], - all_msgs: LogIterable, + all_msgs: LogIterable, frs: Optional[Dict[str, BaseFrameReader]], fingerprint: Optional[str], capture_output: bool ): with self.prefix as p: @@ -241,7 +241,8 @@ def start( self.sockets = [messaging.sub_sock(s, timeout=100) for s in self.cfg.subs] if len(self.cfg.vision_pubs) != 0: - self._setup_vision_ipc(all_msgs) + assert frs is not None + self._setup_vision_ipc(all_msgs, frs) assert self.vipc_server is not None if capture_output: @@ -265,7 +266,7 @@ def stop(self): self.prefix.clean_dirs() self._clean_env() - def run_step(self, msg: capnp._DynamicStructReader, frs: Optional[Dict[str, Any]]) -> List[capnp._DynamicStructReader]: + def run_step(self, msg: capnp._DynamicStructReader, frs: Optional[Dict[str, BaseFrameReader]]) -> List[capnp._DynamicStructReader]: assert self.rc and self.pm and self.sockets and self.process.proc output_msgs = [] @@ -622,7 +623,7 @@ def replay_process_with_name(name: Union[str, Iterable[str]], lr: LogIterable, * def replay_process( - cfg: Union[ProcessConfig, Iterable[ProcessConfig]], lr: LogIterable, frs: Optional[Dict[str, Any]] = None, + cfg: Union[ProcessConfig, Iterable[ProcessConfig]], lr: LogIterable, frs: Optional[Dict[str, BaseFrameReader]] = None, fingerprint: Optional[str] = None, return_all_logs: bool = False, custom_params: Optional[Dict[str, Any]] = None, captured_output_store: Optional[Dict[str, Dict[str, str]]] = None, disable_progress: bool = False ) -> List[capnp._DynamicStructReader]: @@ -650,7 +651,7 @@ def replay_process( def _replay_multi_process( - cfgs: List[ProcessConfig], lr: LogIterable, frs: Optional[Dict[str, Any]], fingerprint: Optional[str], + cfgs: List[ProcessConfig], lr: LogIterable, frs: Optional[Dict[str, BaseFrameReader]], fingerprint: Optional[str], custom_params: Optional[Dict[str, Any]], captured_output_store: Optional[Dict[str, Dict[str, str]]], disable_progress: bool ) -> List[capnp._DynamicStructReader]: if fingerprint is not None: @@ -677,7 +678,7 @@ def _replay_multi_process( for cfg in cfgs: container = ProcessContainer(cfg) containers.append(container) - container.start(params_config, env_config, all_msgs, fingerprint, captured_output_store is not None) + container.start(params_config, env_config, all_msgs, frs, fingerprint, captured_output_store is not None) all_pubs = {pub for container in containers for pub in container.pubs} all_subs = {sub for container in containers for sub in container.subs} From c27e977475e33e19c8042dfead745f5cbc1ad9ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Wed, 25 Oct 2023 16:20:12 -0700 Subject: [PATCH 058/133] URLFile: exception type for failed requests (#30330) URLFileException for URLFile request errors --- tools/lib/url_file.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/lib/url_file.py b/tools/lib/url_file.py index 2f933e3b7f235c4..315ade514bdc801 100644 --- a/tools/lib/url_file.py +++ b/tools/lib/url_file.py @@ -17,6 +17,10 @@ def hash_256(link): return hsh +class URLFileException(Exception): + pass + + class URLFile: _tlocal = threading.local() @@ -158,11 +162,11 @@ def test(debug_type, debug_msg): response_code = c.getinfo(pycurl.RESPONSE_CODE) if response_code == 416: # Requested Range Not Satisfiable - raise Exception(f"Error, range out of bounds {response_code} {headers} ({self._url}): {repr(dats.getvalue())[:500]}") + raise URLFileException(f"Error, range out of bounds {response_code} {headers} ({self._url}): {repr(dats.getvalue())[:500]}") if download_range and response_code != 206: # Partial Content - raise Exception(f"Error, requested range but got unexpected response {response_code} {headers} ({self._url}): {repr(dats.getvalue())[:500]}") + raise URLFileException(f"Error, requested range but got unexpected response {response_code} {headers} ({self._url}): {repr(dats.getvalue())[:500]}") if (not download_range) and response_code != 200: # OK - raise Exception(f"Error {response_code} {headers} ({self._url}): {repr(dats.getvalue())[:500]}") + raise URLFileException(f"Error {response_code} {headers} ({self._url}): {repr(dats.getvalue())[:500]}") ret = dats.getvalue() self._pos += len(ret) From eecdaf9950b150de723b5a5ec94cdbf7a063571a Mon Sep 17 00:00:00 2001 From: mitchellgoffpc Date: Wed, 25 Oct 2023 21:37:54 -0700 Subject: [PATCH 059/133] Added sentry hooks for modeld --- selfdrive/modeld/modeld.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index 5df4e5e17251b63..4ad4038cbc79589 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import sys import os import time import pickle @@ -15,12 +14,14 @@ from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.realtime import config_realtime_process from openpilot.common.transformations.model import get_warp_matrix +from openpilot.selfdrive import sentry from openpilot.selfdrive.modeld.runners import ModelRunner, Runtime from openpilot.selfdrive.modeld.parse_model_outputs import Parser from openpilot.selfdrive.modeld.fill_model_msg import fill_model_msg, fill_pose_msg, PublishState from openpilot.selfdrive.modeld.constants import ModelConstants from openpilot.selfdrive.modeld.models.commonmodel_pyx import ModelFrame, CLContext +PROCESS_NAME = "selfdrive.modeld.modeld" SEND_RAW_PRED = os.getenv('SEND_RAW_PRED') MODEL_PATHS = { @@ -108,8 +109,9 @@ def run(self, buf: VisionBuf, wbuf: VisionBuf, transform: np.ndarray, transform_ def main(): - cloudlog.bind(daemon="selfdrive.modeld.modeld") - setproctitle("selfdrive.modeld.modeld") + sentry.set_tag("daemon", PROCESS_NAME) + cloudlog.bind(daemon=PROCESS_NAME) + setproctitle(PROCESS_NAME) config_realtime_process(7, 54) cl_context = CLContext() @@ -280,4 +282,7 @@ def main(): try: main() except KeyboardInterrupt: - sys.exit() + cloudlog.warning(f"child {PROCESS_NAME} got SIGINT") + except Exception: + sentry.capture_exception() + raise From 91380f085b6fed2e70d66e792d7a3f3d136b8252 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 29 Oct 2023 07:05:13 -1000 Subject: [PATCH 060/133] fix up docker script --- selfdrive/test/docker_common.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/selfdrive/test/docker_common.sh b/selfdrive/test/docker_common.sh index 1b3c70549403263..92da71ba6610c02 100644 --- a/selfdrive/test/docker_common.sh +++ b/selfdrive/test/docker_common.sh @@ -1,17 +1,17 @@ -if [ $1 = "base" ]; then +if [ "$1" = "base" ]; then export DOCKER_IMAGE=openpilot-base export DOCKER_FILE=Dockerfile.openpilot_base -elif [ $1 = "sim" ]; then +elif [ "$1" = "sim" ]; then export DOCKER_IMAGE=openpilot-sim export DOCKER_FILE=tools/sim/Dockerfile.sim -elif [ $1 = "prebuilt" ]; then +elif [ "$1" = "prebuilt" ]; then export DOCKER_IMAGE=openpilot-prebuilt export DOCKER_FILE=Dockerfile.openpilot -elif [ $1 = "cl" ]; then +elif [ "$1" = "cl" ]; then export DOCKER_IMAGE=openpilot-base-cl export DOCKER_FILE=Dockerfile.openpilot_base_cl else - echo "Invalid docker build image $1" + echo "Invalid docker build image: '$1'" exit 1 fi From fe4ad9670179b6f823b7332d5a903a7049a3ac03 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 30 Oct 2023 01:05:59 +0800 Subject: [PATCH 061/133] cabana: support multiple cameras (#30339) support multiple cameras --- tools/cabana/cabana.cc | 12 +++---- tools/cabana/streams/abstractstream.h | 3 -- tools/cabana/streams/replaystream.cc | 29 ++++++++-------- tools/cabana/streams/replaystream.h | 6 ++-- tools/cabana/videowidget.cc | 49 +++++++++++++++++++-------- tools/cabana/videowidget.h | 4 +++ 6 files changed, 61 insertions(+), 42 deletions(-) diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index 33403a2bff9ccdf..205d79577693189 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -26,6 +26,7 @@ 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({"dcam", "load driver camera"}); cmd_parser.addOption({"stream", "read can messages from live streaming"}); cmd_parser.addOption({"panda", "read can messages from panda"}); cmd_parser.addOption({"panda-serial", "read can messages from panda with given serial", "panda-serial"}); @@ -60,13 +61,10 @@ int main(int argc, char *argv[]) { stream = new SocketCanStream(&app, config); } else { 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; - } else if (cmd_parser.isSet("no-vipc")) { - replay_flags |= REPLAY_FLAG_NO_VIPC; - } + if (cmd_parser.isSet("ecam")) replay_flags |= REPLAY_FLAG_ECAM; + if (cmd_parser.isSet("qcam")) replay_flags |= REPLAY_FLAG_QCAMERA; + if (cmd_parser.isSet("dcam")) replay_flags |= REPLAY_FLAG_DCAM; + if (cmd_parser.isSet("no-vipc")) replay_flags |= REPLAY_FLAG_NO_VIPC; const QStringList args = cmd_parser.positionalArguments(); QString route; diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 4a17affebe2b253..02ebc4b5d180e7d 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -70,7 +69,6 @@ class AbstractStream : public QObject { virtual double currentSec() const = 0; virtual double totalSeconds() const { return lastEventMonoTime() / 1e9 - routeStartTime(); } const CanData &lastMessage(const MessageId &id); - virtual VisionStreamType visionStreamType() const { return VISION_STREAM_ROAD; } virtual const Route *route() const { return nullptr; } virtual void setSpeed(float speed) {} virtual double getSpeed() { return 1; } @@ -79,7 +77,6 @@ class AbstractStream : public QObject { const MessageEventsMap &eventsMap() const { return events_; } const std::vector &allEvents() const { return all_events_; } const std::vector &events(const MessageId &id) const; - virtual const std::vector> getTimeline() { return {}; } signals: void paused(); diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index 8a6b806a8ab4f4f..ccf3e7ca0309350 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -35,7 +35,8 @@ void ReplayStream::mergeSegments() { } bool ReplayStream::loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags) { - replay.reset(new Replay(route, {"can", "roadEncodeIdx", "wideRoadEncodeIdx", "carParams"}, {}, {}, nullptr, replay_flags, data_dir, this)); + replay.reset(new Replay(route, {"can", "roadEncodeIdx", "driverEncodeIdx", "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); @@ -84,25 +85,21 @@ AbstractOpenStreamWidget *ReplayStream::widget(AbstractStream **stream) { OpenReplayWidget::OpenReplayWidget(AbstractStream **stream) : AbstractOpenStreamWidget(stream) { // TODO: get route list from api.comma.ai - QGridLayout *grid_layout = new QGridLayout(); + QGridLayout *grid_layout = new QGridLayout(this); grid_layout->addWidget(new QLabel(tr("Route")), 0, 0); grid_layout->addWidget(route_edit = new QLineEdit(this), 0, 1); route_edit->setPlaceholderText(tr("Enter remote route name or click browse to select a local route")); auto file_btn = new QPushButton(tr("Browse..."), this); grid_layout->addWidget(file_btn, 0, 2); - grid_layout->addWidget(new QLabel(tr("Video")), 1, 0); - grid_layout->addWidget(choose_video_cb = new QComboBox(this), 1, 1); - QString items[] = {tr("No Video"), tr("Road Camera"), tr("Wide Road Camera"), tr("Driver Camera"), tr("QCamera")}; - for (int i = 0; i < std::size(items); ++i) { - choose_video_cb->addItem(items[i]); - } - choose_video_cb->setCurrentIndex(1); // default is road camera; + grid_layout->addWidget(new QLabel(tr("Camera")), 1, 0); + QHBoxLayout *camera_layout = new QHBoxLayout(); + for (auto c : {tr("Road camera"), tr("Driver camera"), tr("Wide road camera")}) + camera_layout->addWidget(cameras.emplace_back(new QCheckBox(c, this))); + camera_layout->addStretch(1); + grid_layout->addItem(camera_layout, 1, 1); - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->addLayout(grid_layout); setMinimumWidth(550); - QObject::connect(file_btn, &QPushButton::clicked, [=]() { QString dir = QFileDialog::getExistingDirectory(this, tr("Open Local Route"), settings.last_route_dir); if (!dir.isEmpty()) { @@ -124,9 +121,13 @@ bool OpenReplayWidget::open() { if (!is_valid_format) { QMessageBox::warning(nullptr, tr("Warning"), tr("Invalid route format: '%1'").arg(route)); } else { - uint32_t flags[] = {REPLAY_FLAG_NO_VIPC, REPLAY_FLAG_NONE, REPLAY_FLAG_ECAM, REPLAY_FLAG_DCAM, REPLAY_FLAG_QCAMERA}; auto replay_stream = std::make_unique(qApp); - if (replay_stream->loadRoute(route, data_dir, flags[choose_video_cb->currentIndex()])) { + uint32_t flags = REPLAY_FLAG_NONE; + if (cameras[1]->isChecked()) flags |= REPLAY_FLAG_DCAM; + if (cameras[2]->isChecked()) flags |= REPLAY_FLAG_ECAM; + if (flags == REPLAY_FLAG_NONE && !cameras[0]->isChecked()) flags = REPLAY_FLAG_NO_VIPC; + + if (replay_stream->loadRoute(route, data_dir, flags)) { *stream = replay_stream.release(); } else { QMessageBox::warning(nullptr, tr("Warning"), tr("Failed to load route: '%1'").arg(route)); diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index d69922a432697a4..7f8f8a4d3a5e032 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -1,9 +1,9 @@ #pragma once +#include #include #include #include -#include #include #include "common/prefix.h" @@ -21,7 +21,6 @@ class ReplayStream : public AbstractStream { inline QString routeName() const override { return replay->route()->name(); } inline QString carFingerprint() const override { return replay->carFingerprint().c_str(); } double totalSeconds() const override { return replay->totalSeconds(); } - inline VisionStreamType visionStreamType() const override { return replay->hasFlag(REPLAY_FLAG_ECAM) ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD; } inline QDateTime beginDateTime() const { return replay->route()->datetime(); } inline double routeStartTime() const override { return replay->routeStartTime() / (double)1e9; } inline double currentSec() const override { return replay->currentSeconds(); } @@ -31,7 +30,6 @@ class ReplayStream : public AbstractStream { inline Replay *getReplay() const { return replay.get(); } inline bool isPaused() const override { return replay->isPaused(); } void pause(bool pause) override; - inline const std::vector> getTimeline() override { return replay->getTimeline(); } static AbstractOpenStreamWidget *widget(AbstractStream **stream); signals: @@ -54,5 +52,5 @@ class OpenReplayWidget : public AbstractOpenStreamWidget { private: QLineEdit *route_edit; - QComboBox *choose_video_cb; + std::vector cameras; }; diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index f7f566507ceff2b..7afcc7b9385ee89 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -33,11 +33,9 @@ VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) { main_layout->addLayout(createPlaybackController()); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); - QObject::connect(can, &AbstractStream::paused, this, &VideoWidget::updatePlayBtnState); QObject::connect(can, &AbstractStream::resume, this, &VideoWidget::updatePlayBtnState); QObject::connect(can, &AbstractStream::updated, this, &VideoWidget::updateState); - QObject::connect(&settings, &Settings::changed, this, &VideoWidget::updatePlayBtnState); updatePlayBtnState(); setWhatsThis(tr(R"( @@ -131,10 +129,15 @@ QWidget *VideoWidget::createCameraWidget() { QWidget *w = new QWidget(this); QVBoxLayout *l = new QVBoxLayout(w); l->setContentsMargins(0, 0, 0, 0); + l->setSpacing(0); + + l->addWidget(camera_tab = new TabBar(w)); + camera_tab->setAutoHide(true); + camera_tab->setExpanding(false); QStackedLayout *stacked = new QStackedLayout(); stacked->setStackingMode(QStackedLayout::StackAll); - stacked->addWidget(cam_widget = new CameraWidget("camerad", can->visionStreamType(), false)); + stacked->addWidget(cam_widget = new CameraWidget("camerad", VISION_STREAM_ROAD, false)); cam_widget->setMinimumHeight(MIN_VIDEO_HEIGHT); cam_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); stacked->addWidget(alert_label = new InfoLabel(this)); @@ -146,11 +149,34 @@ QWidget *VideoWidget::createCameraWidget() { setMaximumTime(can->totalSeconds()); QObject::connect(slider, &QSlider::sliderReleased, [this]() { can->seekTo(slider->currentSecond()); }); QObject::connect(slider, &Slider::updateMaximumTime, this, &VideoWidget::setMaximumTime, Qt::QueuedConnection); - QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); QObject::connect(static_cast(can), &ReplayStream::qLogLoaded, slider, &Slider::parseQLog); + QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); + QObject::connect(cam_widget, &CameraWidget::vipcAvailableStreamsUpdated, this, &VideoWidget::vipcAvailableStreamsUpdated); + QObject::connect(camera_tab, &QTabBar::currentChanged, [this](int index) { + if (index != -1) cam_widget->setStreamType((VisionStreamType)camera_tab->tabData(index).toInt()); + }); return w; } +void VideoWidget::vipcAvailableStreamsUpdated(std::set streams) { + static const QString stream_names[] = { + [VISION_STREAM_ROAD] = "Road camera", + [VISION_STREAM_WIDE_ROAD] = "Wide road camera", + [VISION_STREAM_DRIVER] = "Driver camera"}; + + for (int i = 0; i < streams.size(); ++i) { + if (camera_tab->count() <= i) { + camera_tab->addTab(QString()); + } + int type = *std::next(streams.begin(), i); + camera_tab->setTabText(i, stream_names[type]); + camera_tab->setTabData(i, type); + } + while (camera_tab->count() > streams.size()) { + camera_tab->removeTab(camera_tab->count() - 1); + } +} + void VideoWidget::loopPlaybackClicked() { auto replay = qobject_cast(can)->getReplay(); if (replay->hasFlag(REPLAY_FLAG_NO_LOOP)) { @@ -172,12 +198,8 @@ void VideoWidget::updateTimeRange(double min, double max, bool is_zoomed) { skip_to_end_btn->setEnabled(!is_zoomed); return; } - - if (!is_zoomed) { - min = 0; - max = maximum_time; - } - slider->setTimeRange(min, max); + is_zoomed ? slider->setTimeRange(min, max) + : slider->setTimeRange(0, maximum_time); } QString VideoWidget::formatTime(double sec, bool include_milliseconds) { @@ -262,7 +284,7 @@ void Slider::paintEvent(QPaintEvent *ev) { double min = minimum() / factor; double max = maximum() / factor; - for (auto [begin, end, type] : qobject_cast(can)->getTimeline()) { + for (auto [begin, end, type] : qobject_cast(can)->getReplay()->getTimeline()) { if (begin > max || end < min) continue; r.setLeft(((std::max(min, begin) - min) / (max - min)) * width()); @@ -282,8 +304,7 @@ void Slider::paintEvent(QPaintEvent *ev) { void Slider::mousePressEvent(QMouseEvent *e) { QSlider::mousePressEvent(e); if (e->button() == Qt::LeftButton && !isSliderDown()) { - int value = minimum() + ((maximum() - minimum()) * e->x()) / width(); - setValue(value); + setValue(minimum() + ((maximum() - minimum()) * e->x()) / width()); emit sliderReleased(); } } @@ -294,7 +315,7 @@ void Slider::mouseMoveEvent(QMouseEvent *e) { QPixmap thumb = thumbnail(seconds); if (!thumb.isNull()) { int x = std::clamp(pos - thumb.width() / 2, THUMBNAIL_MARGIN, width() - thumb.width() - THUMBNAIL_MARGIN + 1); - int y = -thumb.height() - THUMBNAIL_MARGIN - 6; + int y = -thumb.height() - THUMBNAIL_MARGIN; thumbnail_label.showPixmap(mapToParent(QPoint(x, y)), utils::formatSeconds(seconds), thumb, alertInfo(seconds)); } else { thumbnail_label.hide(); diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 68e046111739653..c2fdb41df817058 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -2,9 +2,11 @@ #include #include +#include #include #include +#include #include #include "selfdrive/ui/qt/widgets/cameraview.h" @@ -70,6 +72,7 @@ class VideoWidget : public QFrame { QWidget *createCameraWidget(); QHBoxLayout *createPlaybackController(); void loopPlaybackClicked(); + void vipcAvailableStreamsUpdated(std::set streams); CameraWidget *cam_widget; double maximum_time = 0; @@ -82,4 +85,5 @@ class VideoWidget : public QFrame { ToolButton *skip_to_end_btn = nullptr; InfoLabel *alert_label = nullptr; Slider *slider = nullptr; + QTabBar *camera_tab = nullptr; }; From 0eea00e887e9e480ea976ccc2eeed1671b2a494d Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Sun, 29 Oct 2023 13:06:34 -0400 Subject: [PATCH 062/133] ui: Always display Wi-Fi list when navigating to Network panel (#30333) * ui: Display Wi-Fi list when navigate to Network panel * pertain to PR description --- selfdrive/ui/qt/network/networking.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/ui/qt/network/networking.cc b/selfdrive/ui/qt/network/networking.cc index 98ecc90fe334666..090b9b578c4a9d8 100644 --- a/selfdrive/ui/qt/network/networking.cc +++ b/selfdrive/ui/qt/network/networking.cc @@ -105,6 +105,7 @@ void Networking::showEvent(QShowEvent *event) { } void Networking::hideEvent(QHideEvent *event) { + main_layout->setCurrentWidget(wifiScreen); wifi->stop(); } From 61288dfe068e6127dcff64b8e7ac81844f7c31ff Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 30 Oct 2023 01:08:28 +0800 Subject: [PATCH 063/133] athenad: fix memory leak in `_do_upload()` (#30237) * fix memory leak * test: stash * clean up * clean up * ruff * rm * add py memory profiler * test compress and no compress * proper test * comment --------- Co-authored-by: Shane Smiskol --- poetry.lock | 15 ++++++++++--- pyproject.toml | 1 + selfdrive/athena/athenad.py | 16 ++++++-------- selfdrive/athena/tests/test_athenad.py | 30 +++++++++++++++++++------- 4 files changed, 41 insertions(+), 21 deletions(-) diff --git a/poetry.lock b/poetry.lock index 93e907a578576cf..a4e47d2359434de 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3472,8 +3472,6 @@ files = [ {file = "pygame-2.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e24d05184e4195fe5ebcdce8b18ecb086f00182b9ae460a86682d312ce8d31f"}, {file = "pygame-2.5.2-cp311-cp311-win32.whl", hash = "sha256:f02c1c7505af18d426d355ac9872bd5c916b27f7b0fe224749930662bea47a50"}, {file = "pygame-2.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:6d58c8cf937815d3b7cdc0fa9590c5129cb2c9658b72d00e8a4568dea2ff1d42"}, - {file = "pygame-2.5.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1a2a43802bb5e89ce2b3b775744e78db4f9a201bf8d059b946c61722840ceea8"}, - {file = "pygame-2.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1c289f2613c44fe70a1e40769de4a49c5ab5a29b9376f1692bb1a15c9c1c9bfa"}, {file = "pygame-2.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:074aa6c6e110c925f7f27f00c7733c6303407edc61d738882985091d1eb2ef17"}, {file = "pygame-2.5.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe0228501ec616779a0b9c4299e837877783e18df294dd690b9ab0eed3d8aaab"}, {file = "pygame-2.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31648d38ecdc2335ffc0e38fb18a84b3339730521505dac68514f83a1092e3f4"}, @@ -3613,6 +3611,17 @@ files = [ [package.dependencies] cffi = ">=1.0.0" +[[package]] +name = "pympler" +version = "1.0.1" +description = "A development tool to measure, monitor and analyze the memory behavior of Python objects." +optional = false +python-versions = ">=3.6" +files = [ + {file = "Pympler-1.0.1-py3-none-any.whl", hash = "sha256:d260dda9ae781e1eab6ea15bacb84015849833ba5555f141d2d9b7b7473b307d"}, + {file = "Pympler-1.0.1.tar.gz", hash = "sha256:993f1a3599ca3f4fcd7160c7545ad06310c9e12f70174ae7ae8d4e25f6c5d3fa"}, +] + [[package]] name = "pyopencl" version = "2023.1.4" @@ -5179,4 +5188,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "acb0688e485872194c21e1313e20fc4a67084893b26e9b8cde1d66e3fdbb1282" +content-hash = "9538e574ca03437994b7b0a0b6cb41842256162a2f14abfd0da26587709f145a" diff --git a/pyproject.toml b/pyproject.toml index b87211cc92204e5..c83669898f06714 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -140,6 +140,7 @@ parameterized = "^0.8" pprofile = "*" pre-commit = "*" pygame = "*" +pympler = "*" pyprof2calltree = "*" pytest = "*" pytest-cov = "*" diff --git a/selfdrive/athena/athenad.py b/selfdrive/athena/athenad.py index 70e18bbedb526aa..c93b434677283f4 100755 --- a/selfdrive/athena/athenad.py +++ b/selfdrive/athena/athenad.py @@ -20,7 +20,7 @@ from datetime import datetime from functools import partial from queue import Queue -from typing import BinaryIO, Callable, Dict, List, Optional, Set, Union, cast +from typing import Callable, Dict, List, Optional, Set, Union, cast import requests from jsonrpc import JSONRPCResponseManager, dispatcher @@ -290,19 +290,15 @@ def _do_upload(upload_item: UploadItem, callback: Optional[Callable] = None) -> compress = True with open(path, "rb") as f: - data: BinaryIO + content = f.read() if compress: cloudlog.event("athena.upload_handler.compress", fn=path, fn_orig=upload_item.path) - compressed = bz2.compress(f.read()) - size = len(compressed) - data = io.BytesIO(compressed) - else: - size = os.fstat(f.fileno()).st_size - data = f + content = bz2.compress(content) + with io.BytesIO(content) as data: return requests.put(upload_item.url, - data=CallbackReader(data, callback, size) if callback else data, - headers={**upload_item.headers, 'Content-Length': str(size)}, + data=CallbackReader(data, callback, len(content)) if callback else data, + headers={**upload_item.headers, 'Content-Length': str(len(content))}, timeout=30) diff --git a/selfdrive/athena/tests/test_athenad.py b/selfdrive/athena/tests/test_athenad.py index 27ccbdccc64b865..e81753a6a01a0f5 100755 --- a/selfdrive/athena/tests/test_athenad.py +++ b/selfdrive/athena/tests/test_athenad.py @@ -9,10 +9,11 @@ import unittest from dataclasses import asdict, replace from datetime import datetime, timedelta +from parameterized import parameterized from typing import Optional from multiprocessing import Process -from pathlib import Path +from pympler.tracker import SummaryTracker from unittest import mock from websocket import ABNF from websocket._exceptions import WebSocketConnectionClosedException @@ -57,10 +58,11 @@ def _wait_for_upload(): break @staticmethod - def _create_file(file: str, parent: Optional[str] = None) -> str: + def _create_file(file: str, parent: Optional[str] = None, data: bytes = b'') -> str: fn = os.path.join(Paths.log_root() if parent is None else parent, file) os.makedirs(os.path.dirname(fn), exist_ok=True) - Path(fn).touch() + with open(fn, 'wb') as f: + f.write(data) return fn @@ -137,19 +139,31 @@ def test_strip_bz2_extension(self): if fn.endswith('.bz2'): self.assertEqual(athenad.strip_bz2_extension(fn), fn[:-4]) - + @parameterized.expand([(True,), (False,)]) @with_http_server - def test_do_upload(self, host): - fn = self._create_file('qlog.bz2') + def test_do_upload(self, compress, host): + # random bytes to ensure rather large object post-compression + fn = self._create_file('qlog', data=os.urandom(10000 * 1024)) - item = athenad.UploadItem(path=fn, url="http://localhost:1238", headers={}, created_at=int(time.time()*1000), id='') + # warm up object tracker + tracker = SummaryTracker() + for _ in range(5): + tracker.diff() + + upload_fn = fn + ('.bz2' if compress else '') + item = athenad.UploadItem(path=upload_fn, url="http://localhost:1238", headers={}, created_at=int(time.time()*1000), id='') with self.assertRaises(requests.exceptions.ConnectionError): athenad._do_upload(item) - item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='') + item = athenad.UploadItem(path=upload_fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='') resp = athenad._do_upload(item) self.assertEqual(resp.status_code, 201) + # assert memory cleaned up + for _type, num_objects, total_size in tracker.diff(): + with self.subTest(_type=_type): + self.assertLess(total_size / 1024, 10, f'Object {_type} ({num_objects=}) grew larger than 10 kB while uploading file') + @with_http_server def test_uploadFileToUrl(self, host): fn = self._create_file('qlog.bz2') From 01610128bb340f83ebf08b344404330806178825 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 31 Oct 2023 00:47:23 +0800 Subject: [PATCH 064/133] cabana: support suppress highlighted bits (#30336) * support suppress highlighted bits d * faster filtering and sorting * improve livestream * specify the context in the connections * remove inline --- tools/cabana/binaryview.cc | 16 +- tools/cabana/chart/chartswidget.cc | 4 +- tools/cabana/chart/signalselector.cc | 6 +- tools/cabana/dbc/dbcfile.cc | 6 +- tools/cabana/dbc/dbcfile.h | 9 +- tools/cabana/dbc/dbcmanager.cc | 11 +- tools/cabana/dbc/dbcmanager.h | 10 +- tools/cabana/detailwidget.cc | 4 +- tools/cabana/detailwidget.h | 4 +- tools/cabana/historylog.cc | 22 +- tools/cabana/historylog.h | 6 +- tools/cabana/mainwin.cc | 27 +-- tools/cabana/messageswidget.cc | 262 ++++++++++------------- tools/cabana/messageswidget.h | 31 +-- tools/cabana/settings.cc | 2 +- tools/cabana/settings.h | 2 +- tools/cabana/signalview.cc | 18 +- tools/cabana/signalview.h | 5 +- tools/cabana/streams/abstractstream.cc | 268 ++++++++++++------------ tools/cabana/streams/abstractstream.h | 80 ++++--- tools/cabana/streams/devicestream.cc | 8 +- tools/cabana/streams/livestream.cc | 33 ++- tools/cabana/streams/livestream.h | 15 +- tools/cabana/streams/pandastream.cc | 10 +- tools/cabana/streams/pandastream.h | 1 - tools/cabana/streams/replaystream.cc | 22 +- tools/cabana/streams/replaystream.h | 4 +- tools/cabana/streams/socketcanstream.cc | 9 +- tools/cabana/streams/socketcanstream.h | 4 - tools/cabana/streamselector.cc | 1 - tools/cabana/tools/findsignal.cc | 12 +- tools/cabana/util.cc | 45 ++-- tools/cabana/util.h | 12 +- tools/cabana/videowidget.cc | 7 +- tools/cabana/videowidget.h | 4 +- 35 files changed, 464 insertions(+), 516 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 5bc88f2d4e7cb4e..c72ebf9d359d730 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -2,6 +2,7 @@ #include +#include #include #include #include @@ -273,7 +274,7 @@ void BinaryViewModel::refresh() { row_count = can->lastMessage(msg_id).dat.size(); items.resize(row_count * column_count); } - int valid_rows = std::min(can->lastMessage(msg_id).dat.size(), row_count); + int valid_rows = std::min(can->lastMessage(msg_id).dat.size(), row_count); for (int i = 0; i < valid_rows * column_count; ++i) { items[i].valid = true; } @@ -311,7 +312,7 @@ void BinaryViewModel::updateState() { int val = ((binary[i] >> (7 - j)) & 1) != 0 ? 1 : 0; // Bit update frequency based highlighting double offset = !item.sigs.empty() ? 50 : 0; - auto n = last_msg.bit_change_counts[i][7 - j]; + auto n = last_msg.last_changes[i].bit_change_counts[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); auto color = item.bg_color; @@ -334,13 +335,8 @@ QVariant BinaryViewModel::headerData(int section, Qt::Orientation orientation, i } QVariant BinaryViewModel::data(const QModelIndex &index, int role) const { - if (role == Qt::ToolTipRole) { - auto item = (const BinaryViewModel::Item *)index.internalPointer(); - if (item && !item->sigs.empty()) { - return signalToolTip(item->sigs.back()); - } - } - return {}; + auto item = (const BinaryViewModel::Item *)index.internalPointer(); + return role == Qt::ToolTipRole && item && !item->sigs.empty() ? signalToolTip(item->sigs.back()) : QVariant(); } // BinaryItemDelegate @@ -388,7 +384,7 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op drawSignalCell(painter, option, index, s); } } - } else if (item->valid) { + } else if (item->valid && item->bg_color.alpha() > 0) { painter->fillRect(option.rect, item->bg_color); } auto color_role = item->sigs.contains(bin_view->hovered_sig) ? QPalette::BrightText : QPalette::Text; diff --git a/tools/cabana/chart/chartswidget.cc b/tools/cabana/chart/chartswidget.cc index 63e103793c45506..0db99063e0be6bc 100644 --- a/tools/cabana/chart/chartswidget.cc +++ b/tools/cabana/chart/chartswidget.cc @@ -100,7 +100,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : align_timer(this), auto_scroll_tim QObject::connect(&auto_scroll_timer, &QTimer::timeout, this, &ChartsWidget::doAutoScroll); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll); QObject::connect(can, &AbstractStream::eventsMerged, this, &ChartsWidget::eventsMerged); - QObject::connect(can, &AbstractStream::updated, this, &ChartsWidget::updateState); + QObject::connect(can, &AbstractStream::msgsReceived, this, &ChartsWidget::updateState); QObject::connect(range_slider, &QSlider::valueChanged, this, &ChartsWidget::setMaxChartRange); QObject::connect(new_plot_btn, &QToolButton::clicked, this, &ChartsWidget::newChart); QObject::connect(remove_all_btn, &QToolButton::clicked, this, &ChartsWidget::removeAll); @@ -324,7 +324,7 @@ void ChartsWidget::updateLayout(bool force) { charts_layout->addWidget(current_charts[i], i / n, i % n); if (current_charts[i]->sigs.empty()) { // the chart will be resized after add signal. delay setVisible to reduce flicker. - QTimer::singleShot(0, [c = current_charts[i]]() { c->setVisible(true); }); + QTimer::singleShot(0, current_charts[i], [c = current_charts[i]]() { c->setVisible(true); }); } else { current_charts[i]->setVisible(true); } diff --git a/tools/cabana/chart/signalselector.cc b/tools/cabana/chart/signalselector.cc index 50fe861a036fd3a..0ddb212a8ad42b0 100644 --- a/tools/cabana/chart/signalselector.cc +++ b/tools/cabana/chart/signalselector.cc @@ -44,9 +44,9 @@ SignalSelector::SignalSelector(QString title, QWidget *parent) : QDialog(parent) auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); main_layout->addWidget(buttonBox, 3, 2); - 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())); + for (const auto &[id, _] : can->lastMessages()) { + if (auto m = dbc()->msg(id)) { + msgs_combo->addItem(QString("%1 (%2)").arg(m->name).arg(id.toString()), QVariant::fromValue(id)); } } msgs_combo->model()->sort(0); diff --git a/tools/cabana/dbc/dbcfile.cc b/tools/cabana/dbc/dbcfile.cc index c923e4d5b27e5fa..a22d9792128061b 100644 --- a/tools/cabana/dbc/dbcfile.cc +++ b/tools/cabana/dbc/dbcfile.cc @@ -4,10 +4,8 @@ #include #include #include -#include -#include -DBCFile::DBCFile(const QString &dbc_file_name, QObject *parent) : QObject(parent) { +DBCFile::DBCFile(const QString &dbc_file_name) { QFile file(dbc_file_name); if (file.open(QIODevice::ReadOnly)) { name_ = QFileInfo(dbc_file_name).baseName(); @@ -22,7 +20,7 @@ DBCFile::DBCFile(const QString &dbc_file_name, QObject *parent) : QObject(parent } } -DBCFile::DBCFile(const QString &name, const QString &content, QObject *parent) : QObject(parent), name_(name), filename("") { +DBCFile::DBCFile(const QString &name, const QString &content) : name_(name), filename("") { // Open from clipboard parse(content); } diff --git a/tools/cabana/dbc/dbcfile.h b/tools/cabana/dbc/dbcfile.h index a3ab1cebe401117..ade6b249e2b16f9 100644 --- a/tools/cabana/dbc/dbcfile.h +++ b/tools/cabana/dbc/dbcfile.h @@ -1,18 +1,15 @@ #pragma once #include -#include #include "tools/cabana/dbc/dbc.h" const QString AUTO_SAVE_EXTENSION = ".tmp"; -class DBCFile : public QObject { - Q_OBJECT - +class DBCFile { public: - DBCFile(const QString &dbc_file_name, QObject *parent=nullptr); - DBCFile(const QString &name, const QString &content, QObject *parent=nullptr); + DBCFile(const QString &dbc_file_name); + DBCFile(const QString &name, const QString &content); ~DBCFile() {} bool save(); diff --git a/tools/cabana/dbc/dbcmanager.cc b/tools/cabana/dbc/dbcmanager.cc index 459ca0111d5310a..87a7d962c558e6c 100644 --- a/tools/cabana/dbc/dbcmanager.cc +++ b/tools/cabana/dbc/dbcmanager.cc @@ -7,7 +7,7 @@ bool DBCManager::open(const SourceSet &sources, const QString &dbc_file_name, QS try { auto it = std::find_if(dbc_files.begin(), dbc_files.end(), [&](auto &f) { return f.second && f.second->filename == dbc_file_name; }); - auto file = (it != dbc_files.end()) ? it->second : std::make_shared(dbc_file_name, this); + auto file = (it != dbc_files.end()) ? it->second : std::make_shared(dbc_file_name); for (auto s : sources) { dbc_files[s] = file; } @@ -22,7 +22,7 @@ bool DBCManager::open(const SourceSet &sources, const QString &dbc_file_name, QS bool DBCManager::open(const SourceSet &sources, const QString &name, const QString &content, QString *error) { try { - auto file = std::make_shared(name, content, this); + auto file = std::make_shared(name, content); for (auto s : sources) { dbc_files[s] = file; } @@ -189,6 +189,13 @@ const SourceSet DBCManager::sources(const DBCFile *dbc_file) const { return sources; } +QString toString(const SourceSet &ss) { + return std::accumulate(ss.cbegin(), ss.cend(), QString(), [](QString str, int source) { + if (!str.isEmpty()) str += ", "; + return str + (source == -1 ? QStringLiteral("all") : QString::number(source)); + }); +} + DBCManager *dbc() { static DBCManager dbc_manager(nullptr); return &dbc_manager; diff --git a/tools/cabana/dbc/dbcmanager.h b/tools/cabana/dbc/dbcmanager.h index 5f782fc930ad6f3..53a77a2c13357bc 100644 --- a/tools/cabana/dbc/dbcmanager.h +++ b/tools/cabana/dbc/dbcmanager.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -66,15 +67,8 @@ class DBCManager : public QObject { DBCManager *dbc(); +QString toString(const SourceSet &ss); inline QString msgName(const MessageId &id) { auto msg = dbc()->msg(id); return msg ? msg->name : UNTITLED; } - -inline QString toString(const SourceSet &ss) { - QStringList ret; - for (auto s : ss) { - ret << (s == -1 ? QString("all") : QString::number(s)); - } - return ret.join(", "); -} diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 472ffce104db0b9..7befadb72271694 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -147,8 +147,8 @@ void DetailWidget::refresh() { warning_widget->setVisible(!warnings.isEmpty()); } -void DetailWidget::updateState(const QHash *msgs) { - if ((msgs && !msgs->contains(msg_id))) +void DetailWidget::updateState(const std::set *msgs) { + if ((msgs && !msgs->count(msg_id))) return; if (tab_widget->currentIndex() == 0) diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 5bb4b7f305b67b5..15e1ee5f2f954b1 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "selfdrive/ui/qt/widgets/controls.h" #include "tools/cabana/binaryview.h" @@ -11,7 +12,6 @@ #include "tools/cabana/historylog.h" #include "tools/cabana/signalview.h" -class MainWindow; class EditMessageDialog : public QDialog { public: EditMessageDialog(const MessageId &msg_id, const QString &title, int size, QWidget *parent); @@ -39,7 +39,7 @@ class DetailWidget : public QWidget { void showTabBarContextMenu(const QPoint &pt); void editMsg(); void removeMsg(); - void updateState(const QHash * msgs = nullptr); + void updateState(const std::set *msgs = nullptr); MessageId msg_id; QLabel *warning_icon, *warning_label; diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 53305499635dafb..b3440b557bcb7c3 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -7,7 +7,6 @@ #include #include "tools/cabana/commands.h" -// HistoryLogModel QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { const bool show_signals = display_signals_mode && sigs.size() > 0; @@ -17,11 +16,11 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { return QString::number((m.mono_time / (double)1e9) - can->routeStartTime(), 'f', 2); } int i = index.column() - 1; - return show_signals ? QString::number(m.sig_values[i], 'f', sigs[i]->precision) : toHex(m.data); + return show_signals ? QString::number(m.sig_values[i], 'f', sigs[i]->precision) : QString(); } else if (role == ColorsRole) { - return QVariant::fromValue(m.colors); + return QVariant::fromValue((void *)(&m.colors)); } else if (role == BytesRole) { - return m.data; + return QVariant::fromValue((void *)(&m.data)); } else if (role == Qt::TextAlignmentRole) { return (uint32_t)(Qt::AlignRight | Qt::AlignVCenter); } @@ -123,7 +122,7 @@ void HistoryLogModel::fetchMore(const QModelIndex &parent) { template std::deque HistoryLogModel::fetchData(InputIt first, InputIt last, uint64_t min_time) { std::deque msgs; - QVector values(sigs.size()); + std::vector values(sigs.size()); for (; first != last && (*first)->mono_time > min_time; ++first) { const CanEvent *e = *first; for (int i = 0; i < sigs.size(); ++i) { @@ -132,7 +131,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 = e->mono_time; - m.data = QByteArray((const char *)e->dat, e->size); + m.data.assign(e->dat, e->dat + e->size); m.sig_values = values; if (msgs.size() >= batch_size && min_time == 0) { return msgs; @@ -146,7 +145,7 @@ std::deque HistoryLogModel::fetchData(uint64_t from_ti const auto &events = can->events(msg_id); const auto freq = can->lastMessage(msg_id).freq; const bool update_colors = !display_signals_mode || sigs.empty(); - + const std::vector no_mask; const auto speed = can->getSpeed(); if (dynamic_mode) { auto first = std::upper_bound(events.rbegin(), events.rend(), from_time, [](uint64_t ts, auto e) { @@ -155,7 +154,7 @@ std::deque HistoryLogModel::fetchData(uint64_t from_ti 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(msg_id, it->data.data(), it->data.size(), it->mono_time / (double)1e9, speed, nullptr, freq); + hex_colors.compute(msg_id, it->data.data(), it->data.size(), it->mono_time / (double)1e9, speed, no_mask, freq); it->colors = hex_colors.colors; } } @@ -166,7 +165,7 @@ std::deque HistoryLogModel::fetchData(uint64_t from_ti auto msgs = fetchData(first, events.cend(), 0); if (update_colors) { for (auto it = msgs.begin(); it != msgs.end(); ++it) { - hex_colors.compute(msg_id, it->data.data(), it->data.size(), it->mono_time / (double)1e9, speed, nullptr, freq); + hex_colors.compute(msg_id, it->data.data(), it->data.size(), it->mono_time / (double)1e9, speed, no_mask, freq); it->colors = hex_colors.colors; } } @@ -177,7 +176,7 @@ std::deque HistoryLogModel::fetchData(uint64_t from_ti // HeaderView QSize HeaderView::sectionSizeFromContents(int logicalIndex) const { - static QSize time_col_size = fontMetrics().boundingRect({0, 0, 200, 200}, defaultAlignment(), "000000.000").size() + QSize(10, 6); + static const 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 { @@ -237,10 +236,11 @@ LogsWidget::LogsWidget(QWidget *parent) : QFrame(parent) { 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::AlignRight | (Qt::Alignment)Qt::TextWordWrap); logs->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + logs->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); + logs->verticalHeader()->setDefaultSectionSize(delegate->sizeForBytes(8).height()); logs->verticalHeader()->setVisible(false); logs->setFrameShape(QFrame::NoFrame); diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index a68fbdbf435c152..154b139fb072c60 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -46,9 +46,9 @@ public slots: public: struct Message { uint64_t mono_time = 0; - QVector sig_values; - QByteArray data; - QVector colors; + std::vector sig_values; + std::vector data; + std::vector colors; }; template diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 4f27dcf5ed30fb0..0053b08fd29bfe5 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -21,6 +21,7 @@ #include "tools/cabana/commands.h" #include "tools/cabana/streamselector.h" #include "tools/cabana/tools/findsignal.h" +#include "tools/replay/replay.h" MainWindow::MainWindow() : QMainWindow() { createDockWindows(); @@ -84,8 +85,8 @@ void MainWindow::createActions() { close_stream_act->setEnabled(false); file_menu->addSeparator(); - file_menu->addAction(tr("New DBC File"), [this]() { newFile(); })->setShortcuts(QKeySequence::New); - file_menu->addAction(tr("Open DBC File..."), [this]() { openFile(); })->setShortcuts(QKeySequence::Open); + file_menu->addAction(tr("New DBC File"), [this]() { newFile(); }, QKeySequence::New); + file_menu->addAction(tr("Open DBC File..."), [this]() { openFile(); }, QKeySequence::Open); manage_dbcs_menu = file_menu->addMenu(tr("Manage &DBC Files")); @@ -111,19 +112,15 @@ void MainWindow::createActions() { file_menu->addAction(tr("Load DBC From Clipboard"), [=]() { loadFromClipboard(); }); file_menu->addSeparator(); - save_dbc = file_menu->addAction(tr("Save DBC..."), this, &MainWindow::save); - save_dbc->setShortcuts(QKeySequence::Save); - - save_dbc_as = file_menu->addAction(tr("Save DBC As..."), this, &MainWindow::saveAs); - save_dbc_as->setShortcuts(QKeySequence::SaveAs); - + save_dbc = file_menu->addAction(tr("Save DBC..."), this, &MainWindow::save, QKeySequence::Save); + save_dbc_as = file_menu->addAction(tr("Save DBC As..."), this, &MainWindow::saveAs, QKeySequence::SaveAs); copy_dbc_to_clipboard = file_menu->addAction(tr("Copy DBC To Clipboard"), this, &MainWindow::saveToClipboard); file_menu->addSeparator(); - file_menu->addAction(tr("Settings..."), this, &MainWindow::setOption)->setShortcuts(QKeySequence::Preferences); + file_menu->addAction(tr("Settings..."), this, &MainWindow::setOption, QKeySequence::Preferences); file_menu->addSeparator(); - file_menu->addAction(tr("E&xit"), qApp, &QApplication::closeAllWindows)->setShortcuts(QKeySequence::Quit); + file_menu->addAction(tr("E&xit"), qApp, &QApplication::closeAllWindows, QKeySequence::Quit); // Edit Menu QMenu *edit_menu = menuBar()->addMenu(tr("&Edit")); @@ -157,7 +154,7 @@ void MainWindow::createActions() { // Help Menu QMenu *help_menu = menuBar()->addMenu(tr("&Help")); - help_menu->addAction(tr("Help"), this, &MainWindow::onlineHelp)->setShortcuts(QKeySequence::HelpContents); + help_menu->addAction(tr("Help"), this, &MainWindow::onlineHelp, QKeySequence::HelpContents); help_menu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); } @@ -374,7 +371,7 @@ void MainWindow::eventsMerged() { auto dbc_name = fingerprint_to_dbc[car_fingerprint]; if (dbc_name != QJsonValue::Undefined) { // Prevent dialog that load autosaved file from blocking replay->start(). - QTimer::singleShot(0, [dbc_name, this]() { loadDBCFromOpendbc(dbc_name.toString()); }); + QTimer::singleShot(0, this, [dbc_name, this]() { loadDBCFromOpendbc(dbc_name.toString()); }); } } } @@ -471,11 +468,7 @@ void MainWindow::saveFileToClipboard(DBCFile *dbc_file) { void MainWindow::updateLoadSaveMenus() { int cnt = dbc()->nonEmptyDBCCount(); - if (cnt > 1) { - save_dbc->setText(tr("Save %1 DBCs...").arg(dbc()->dbcCount())); - } else { - save_dbc->setText(tr("Save DBC...")); - } + save_dbc->setText(cnt > 1 ? tr("Save %1 DBCs...").arg(cnt) : tr("Save DBC...")); save_dbc->setEnabled(cnt > 0); save_dbc_as->setEnabled(cnt == 1); diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index aea09c55dee1523..29596e325323563 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -11,11 +11,6 @@ #include "tools/cabana/commands.h" -static QString msg_node_from_id(const MessageId &id) { - auto msg = dbc()->msg(id); - return msg ? msg->transmitter : QString(); -} - MessagesWidget::MessagesWidget(QWidget *parent) : menu(new QMenu(this)), QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); @@ -23,12 +18,10 @@ MessagesWidget::MessagesWidget(QWidget *parent) : menu(new QMenu(this)), QWidget // toolbar main_layout->addWidget(createToolBar()); // message table - view = new MessageView(this); - model = new MessageListModel(this); - header = new MessageViewHeader(this); - view->setItemDelegate(delegate = new MessageBytesDelegate(view, settings.multiple_lines_bytes)); - view->setHeader(header); - view->setModel(model); + main_layout->addWidget(view = new MessageView(this)); + view->setItemDelegate(delegate = new MessageBytesDelegate(view, settings.multiple_lines_hex)); + view->setModel(model = new MessageListModel(this)); + view->setHeader(header = new MessageViewHeader(this)); view->setSortingEnabled(true); view->sortByColumn(MessageListModel::Column::NAME, Qt::AscendingOrder); view->setAllColumnsShowFocus(true); @@ -36,6 +29,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : menu(new QMenu(this)), QWidget view->setItemsExpandable(false); view->setIndentation(0); view->setRootIsDecorated(false); + view->setUniformRowHeights(!settings.multiple_lines_hex); // Must be called before setting any header parameters to avoid overriding restoreHeaderState(settings.message_header_state); @@ -44,15 +38,14 @@ MessagesWidget::MessagesWidget(QWidget *parent) : menu(new QMenu(this)), QWidget header->setStretchLastSection(true); header->setContextMenuPolicy(Qt::CustomContextMenu); - main_layout->addWidget(view); - // 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); - QCheckBox *suppress_defined_signals = new QCheckBox(tr("Suppress Defined Signals"), this); + suppress_layout->addWidget(suppress_add = new QPushButton("Suppress Highlighted")); + suppress_layout->addWidget(suppress_clear = new QPushButton()); + suppress_clear->setToolTip(tr("Clear suppressed")); + suppress_layout->addStretch(1); + QCheckBox *suppress_defined_signals = new QCheckBox(tr("Suppress Signals"), this); + suppress_defined_signals->setToolTip(tr("Suppress defined signals")); suppress_defined_signals->setChecked(settings.suppress_defined_signals); suppress_layout->addWidget(suppress_defined_signals); main_layout->addLayout(suppress_layout); @@ -62,10 +55,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : menu(new QMenu(this)), QWidget QObject::connect(header, &MessageViewHeader::filtersUpdated, model, &MessageListModel::setFilterStrings); QObject::connect(header, &MessageViewHeader::customContextMenuRequested, this, &MessagesWidget::headerContextMenuEvent); QObject::connect(view->horizontalScrollBar(), &QScrollBar::valueChanged, header, &MessageViewHeader::updateHeaderPositions); - QObject::connect(suppress_defined_signals, &QCheckBox::stateChanged, [=](int state) { - settings.suppress_defined_signals = (state == Qt::Checked); - emit settings.changed(); - }); + QObject::connect(suppress_defined_signals, &QCheckBox::stateChanged, can, &AbstractStream::suppressDefinedSignals); QObject::connect(can, &AbstractStream::msgsReceived, model, &MessageListModel::msgsReceived); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &MessagesWidget::dbcModified); QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &MessagesWidget::dbcModified); @@ -76,24 +66,17 @@ MessagesWidget::MessagesWidget(QWidget *parent) : menu(new QMenu(this)), QWidget view->updateBytesSectionSize(); }); QObject::connect(view->selectionModel(), &QItemSelectionModel::currentChanged, [=](const QModelIndex ¤t, const QModelIndex &previous) { - if (current.isValid() && current.row() < model->msgs.size()) { - auto &id = model->msgs[current.row()]; + if (current.isValid() && current.row() < model->items_.size()) { + const auto &id = model->items_[current.row()].id; if (!current_msg_id || id != *current_msg_id) { current_msg_id = id; emit msgSelectionChanged(*current_msg_id); } } }); - QObject::connect(suppress_add, &QPushButton::clicked, [=]() { - model->suppress(); - updateSuppressedButtons(); - }); - QObject::connect(suppress_clear, &QPushButton::clicked, [=]() { - model->clearSuppress(); - updateSuppressedButtons(); - }); - - updateSuppressedButtons(); + QObject::connect(suppress_add, &QPushButton::clicked, this, &MessagesWidget::suppressHighlighted); + QObject::connect(suppress_clear, &QPushButton::clicked, this, &MessagesWidget::suppressHighlighted); + suppressHighlighted(); setWhatsThis(tr(R"( Message View
@@ -126,19 +109,22 @@ void MessagesWidget::dbcModified() { } void MessagesWidget::selectMessage(const MessageId &msg_id) { - auto it = std::find(model->msgs.cbegin(), model->msgs.cend(), msg_id); - if (it != model->msgs.cend()) { - view->setCurrentIndex(model->index(std::distance(model->msgs.cbegin(), it), 0)); + auto it = std::find_if(model->items_.cbegin(), model->items_.cend(), + [&msg_id](auto &item) { return item.id == msg_id; }); + if (it != model->items_.cend()) { + view->setCurrentIndex(model->index(std::distance(model->items_.cbegin(), it), 0)); } } -void MessagesWidget::updateSuppressedButtons() { - if (model->suppressed_bytes.empty()) { - suppress_clear->setEnabled(false); - suppress_clear->setText("Clear Suppressed"); - } else { +void MessagesWidget::suppressHighlighted() { + if (sender() == suppress_add) { + size_t n = can->suppressHighlighted(); + suppress_clear->setText(tr("Clear (%1)").arg(n)); suppress_clear->setEnabled(true); - suppress_clear->setText(QString("Clear Suppressed (%1)").arg(model->suppressed_bytes.size())); + } else { + can->clearSuppressed(); + suppress_clear->setText(tr("Clear")); + suppress_clear->setEnabled(false); } } @@ -160,12 +146,13 @@ void MessagesWidget::menuAboutToShow() { menu->addSeparator(); auto action = menu->addAction(tr("Mutlti-Line bytes"), this, &MessagesWidget::setMultiLineBytes); action->setCheckable(true); - action->setChecked(settings.multiple_lines_bytes); + action->setChecked(settings.multiple_lines_hex); } void MessagesWidget::setMultiLineBytes(bool multi) { - settings.multiple_lines_bytes = multi; + settings.multiple_lines_hex = multi; delegate->setMultipleLines(multi); + view->setUniformRowHeights(!multi); view->updateBytesSectionSize(); view->doItemsLayout(); } @@ -188,7 +175,7 @@ QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, } QVariant MessageListModel::data(const QModelIndex &index, int role) const { - if (!index.isValid() || index.row() >= msgs.size()) return {}; + if (!index.isValid() || index.row() >= items_.size()) return {}; auto getFreq = [](const CanData &d) { if (d.freq > 0 && (can->currentSec() - d.ts - 1.0 / settings.fps) < (5.0 / d.freq)) { @@ -198,33 +185,24 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { } }; - const auto &id = msgs[index.row()]; - auto &can_data = can->lastMessage(id); + const auto &item = items_[index.row()]; if (role == Qt::DisplayRole) { switch (index.column()) { - case Column::NAME: return msgName(id); - case Column::SOURCE: return id.source != INVALID_SOURCE ? QString::number(id.source) : "N/A"; - case Column::ADDRESS: return QString::number(id.address, 16); - case Column::NODE: return msg_node_from_id(id); - case Column::FREQ: return id.source != INVALID_SOURCE ? getFreq(can_data) : "N/A"; - case Column::COUNT: return id.source != INVALID_SOURCE ? QString::number(can_data.count) : "N/A"; - case Column::DATA: return id.source != INVALID_SOURCE ? toHex(can_data.dat) : "N/A"; + case Column::NAME: return item.name; + case Column::SOURCE: return item.id.source != INVALID_SOURCE ? QString::number(item.id.source) : "N/A"; + case Column::ADDRESS: return QString::number(item.id.address, 16); + case Column::NODE: return item.node; + case Column::FREQ: return item.id.source != INVALID_SOURCE ? getFreq(*item.data) : "N/A"; + case Column::COUNT: return item.id.source != INVALID_SOURCE ? QString::number(item.data->count) : "N/A"; + case Column::DATA: return item.id.source != INVALID_SOURCE ? "" : "N/A"; } } else if (role == ColorsRole) { - 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 QVariant::fromValue(colors); - } else if (role == BytesRole && index.column() == Column::DATA && id.source != INVALID_SOURCE) { - return can_data.dat; + return QVariant::fromValue((void*)(&item.data->colors)); + } else if (role == BytesRole && index.column() == Column::DATA && item.id.source != INVALID_SOURCE) { + return QVariant::fromValue((void*)(&item.data->dat)); } else if (role == Qt::ToolTipRole && index.column() == Column::NAME) { - auto msg = dbc()->msg(id); - auto tooltip = msg ? msg->name : UNTITLED; + auto msg = dbc()->msg(item.id); + auto tooltip = item.name; if (msg && !msg->comment.isEmpty()) tooltip += "
" + msg->comment + ""; return tooltip; } @@ -232,31 +210,31 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { } void MessageListModel::setFilterStrings(const QMap &filters) { - filter_str = filters; + filters_ = filters; filterAndSort(); } void MessageListModel::dbcModified() { - dbc_address.clear(); + dbc_messages_.clear(); for (const auto &[_, m] : dbc()->getMessages(-1)) { - dbc_address.insert(m.address); + dbc_messages_.insert(MessageId{.source = INVALID_SOURCE, .address = m.address}); } - filterAndSort(); + filterAndSort(true); } -void MessageListModel::sortMessages(std::vector &new_msgs) { - auto do_sort = [order = sort_order](std::vector &m, auto proj) { - std::sort(m.begin(), m.end(), [order, proj = std::move(proj)](auto &l, auto &r) { +void MessageListModel::sortItems(std::vector &items) { + auto do_sort = [order = sort_order](std::vector &m, auto proj) { + std::stable_sort(m.begin(), m.end(), [order, proj = std::move(proj)](auto &l, auto &r) { return order == Qt::AscendingOrder ? proj(l) < proj(r) : proj(l) > proj(r); }); }; switch (sort_column) { - case Column::NAME: do_sort(new_msgs, [](auto &id) { return std::make_pair(msgName(id), id); }); break; - case Column::SOURCE: do_sort(new_msgs, [](auto &id) { return std::tie(id.source, id); }); break; - case Column::ADDRESS: do_sort(new_msgs, [](auto &id) { return std::tie(id.address, id);}); break; - case Column::NODE: do_sort(new_msgs, [](auto &id) { return std::make_pair(msg_node_from_id(id), id);}); break; - case Column::FREQ: do_sort(new_msgs, [](auto &id) { return std::tie(can->lastMessage(id).freq, id); }); break; - case Column::COUNT: do_sort(new_msgs, [](auto &id) { return std::tie(can->lastMessage(id).count, id); }); break; + case Column::NAME: do_sort(items, [](auto &item) { return std::tie(item.name, item.id); }); break; + case Column::SOURCE: do_sort(items, [](auto &item) { return std::tie(item.id.source, item.id); }); break; + case Column::ADDRESS: do_sort(items, [](auto &item) { return std::tie(item.id.address, item.id);}); break; + case Column::NODE: do_sort(items, [](auto &item) { return std::tie(item.node, item.id);}); break; + case Column::FREQ: do_sort(items, [](auto &item) { return std::tie(item.data->freq, item.id); }); break; + case Column::COUNT: do_sort(items, [](auto &item) { return std::tie(item.data->count, item.id); }); break; } } @@ -275,83 +253,85 @@ static bool parseRange(const QString &filter, uint32_t value, int base = 10) { return ok && value >= min && value <= max; } -bool MessageListModel::matchMessage(const MessageId &id, const CanData &data, const QMap &filters) { +bool MessageListModel::match(const MessageListModel::Item &item) { + if (filters_.isEmpty()) + return true; + bool match = true; - for (auto it = filters.cbegin(); it != filters.cend() && match; ++it) { + for (auto it = filters_.cbegin(); it != filters_.cend() && match; ++it) { const QString &txt = it.value(); - QRegularExpression re(txt, QRegularExpression::CaseInsensitiveOption | QRegularExpression::DotMatchesEverythingOption); switch (it.key()) { case Column::NAME: { - const auto msg = dbc()->msg(id); - match = re.match(msg ? msg->name : UNTITLED).hasMatch(); - match = match || (msg && std::any_of(msg->sigs.cbegin(), msg->sigs.cend(), - [&re](const auto &s) { return re.match(s->name).hasMatch(); })); + match = item.name.contains(txt, Qt::CaseInsensitive); + if (!match) { + const auto m = dbc()->msg(item.id); + match = m && std::any_of(m->sigs.cbegin(), m->sigs.cend(), + [&txt](const auto &s) { return s->name.contains(txt, Qt::CaseInsensitive); }); + } break; } case Column::SOURCE: - match = parseRange(txt, id.source); + match = parseRange(txt, item.id.source); break; - case Column::ADDRESS: { - match = re.match(QString::number(id.address, 16)).hasMatch(); - match = match || parseRange(txt, id.address, 16); + case Column::ADDRESS: + match = QString::number(item.id.address, 16).contains(txt, Qt::CaseInsensitive); + match = match || parseRange(txt, item.id.address, 16); break; - } case Column::NODE: - match = re.match(msg_node_from_id(id)).hasMatch(); + match = item.node.contains(txt, Qt::CaseInsensitive); break; case Column::FREQ: // TODO: Hide stale messages? - match = parseRange(txt, data.freq); + match = parseRange(txt, item.data->freq); break; case Column::COUNT: - match = parseRange(txt, data.count); + match = parseRange(txt, item.data->count); break; - case Column::DATA: { - match = QString(data.dat.toHex()).contains(txt, Qt::CaseInsensitive); - match = match || re.match(QString(data.dat.toHex())).hasMatch(); - match = match || re.match(QString(data.dat.toHex(' '))).hasMatch(); + case Column::DATA: + match = utils::toHex(item.data->dat).contains(txt, Qt::CaseInsensitive); break; - } } } return match; } -void MessageListModel::filterAndSort() { - std::vector new_msgs; - new_msgs.reserve(can->last_msgs.size() + dbc_address.size()); - - auto address = dbc_address; - for (auto it = can->last_msgs.cbegin(); it != can->last_msgs.cend(); ++it) { - if (filter_str.isEmpty() || matchMessage(it.key(), it.value(), filter_str)) { - new_msgs.push_back(it.key()); - } - address.remove(it.key().address); +void MessageListModel::filterAndSort(bool force_reset) { + // merge CAN and DBC messages + std::vector all_messages; + all_messages.reserve(can->lastMessages().size() + dbc_messages_.size()); + auto dbc_msgs = dbc_messages_; + for (const auto &[id, m] : can->lastMessages()) { + all_messages.push_back(id); + dbc_msgs.erase(MessageId{.source = INVALID_SOURCE, .address = id.address}); } + std::copy(dbc_msgs.begin(), dbc_msgs.end(), std::back_inserter(all_messages)); - // merge all DBC messages - for (auto &addr : address) { - MessageId id{.source = INVALID_SOURCE, .address = addr}; - if (filter_str.isEmpty() || matchMessage(id, {}, filter_str)) { - new_msgs.push_back(id); - } + // filter and sort + std::vector items; + for (const auto &id : all_messages) { + auto msg = dbc()->msg(id); + Item item = {.id = id, + .name = msg ? msg->name : UNTITLED, + .node = msg ? msg->transmitter : QString(), + .data = &can->lastMessage(id)}; + if (match(item)) + items.emplace_back(item); } + sortItems(items); - sortMessages(new_msgs); - - if (msgs != new_msgs) { + if (force_reset || items_ != items) { beginResetModel(); - msgs = std::move(new_msgs); + items_ = std::move(items); endResetModel(); } } -void MessageListModel::msgsReceived(const QHash *new_msgs, bool has_new_ids) { - if (has_new_ids || filter_str.contains(Column::FREQ) || filter_str.contains(Column::COUNT) || filter_str.contains(Column::DATA)) { +void MessageListModel::msgsReceived(const std::set *new_msgs, bool has_new_ids) { + if (has_new_ids || filters_.contains(Column::FREQ) || filters_.contains(Column::COUNT) || filters_.contains(Column::DATA)) { filterAndSort(); } - for (int i = 0; i < msgs.size(); ++i) { - if (new_msgs->contains(msgs[i])) { + for (int i = 0; i < items_.size(); ++i) { + if (!new_msgs || new_msgs->count(items_[i].id)) { for (int col = Column::FREQ; col < columnCount(); ++col) emit dataChanged(index(i, col), index(i, col), {Qt::DisplayRole}); } @@ -359,31 +339,13 @@ void MessageListModel::msgsReceived(const QHash *new_msgs, b } void MessageListModel::sort(int column, Qt::SortOrder order) { - if (column != columnCount() - 1) { + if (column != Column::DATA) { sort_column = column; sort_order = order; filterAndSort(); } } -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(); -} - // MessageView void MessageView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { @@ -414,14 +376,11 @@ void MessageView::updateBytesSectionSize() { auto delegate = ((MessageBytesDelegate *)itemDelegate()); int max_bytes = 8; if (!delegate->multipleLines()) { - for (auto it = can->last_msgs.constBegin(); it != can->last_msgs.constEnd(); ++it) { - max_bytes = std::max(max_bytes, it.value().dat.size()); + for (const auto &[_, m] : can->lastMessages()) { + max_bytes = std::max(max_bytes, m.dat.size()); } } - int width = delegate->widthForBytes(max_bytes); - if (header()->sectionSize(MessageListModel::Column::DATA) != width) { - header()->resizeSection(MessageListModel::Column::DATA, width); - } + header()->resizeSection(MessageListModel::Column::DATA, delegate->sizeForBytes(max_bytes).width()); } // MessageViewHeader @@ -446,8 +405,7 @@ void MessageViewHeader::updateHeaderPositions() { for (int i = 0; i < count(); i++) { if (editors[i]) { int h = editors[i]->sizeHint().height(); - editors[i]->move(sectionViewportPosition(i), sz.height()); - editors[i]->resize(sectionSize(i), h); + editors[i]->setGeometry(sectionViewportPosition(i), sz.height(), sectionSize(i), h); editors[i]->setHidden(isSectionHidden(i)); } } diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 11d95dd3f2b67ec..063154a2e54fc12 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -9,7 +10,6 @@ #include #include #include -#include #include #include @@ -34,23 +34,28 @@ Q_OBJECT QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override { return Column::DATA + 1; } QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - int rowCount(const QModelIndex &parent = QModelIndex()) const override { return msgs.size(); } + int rowCount(const QModelIndex &parent = QModelIndex()) const override { return items_.size(); } void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; void setFilterStrings(const QMap &filters); - void msgsReceived(const QHash *new_msgs, bool has_new_ids); - void filterAndSort(); - void suppress(); - void clearSuppress(); + void msgsReceived(const std::set *new_msgs, bool has_new_ids); + void filterAndSort(bool force_reset = false); void dbcModified(); - std::vector msgs; - QSet> suppressed_bytes; + + struct Item { + MessageId id; + QString name; + QString node; + const CanData *data; + bool operator==(const Item &other) const { return id == other.id; } + }; + std::vector items_; private: - void sortMessages(std::vector &new_msgs); - bool matchMessage(const MessageId &id, const CanData &data, const QMap &filters); + void sortItems(std::vector &items); + bool match(const MessageListModel::Item &id); - QMap filter_str; - QSet dbc_address; + QMap filters_; + std::set dbc_messages_; int sort_column = 0; Qt::SortOrder sort_order = Qt::AscendingOrder; }; @@ -91,7 +96,7 @@ class MessagesWidget : public QWidget { void selectMessage(const MessageId &message_id); QByteArray saveHeaderState() const { return view->header()->saveState(); } bool restoreHeaderState(const QByteArray &state) const { return view->header()->restoreState(state); } - void updateSuppressedButtons(); + void suppressHighlighted(); public slots: void dbcModified(); diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index ac8d45007d65a27..17de0a1c0ad185d 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -33,7 +33,7 @@ void settings_op(SettingOperation op) { op(s, "chart_series_type", settings.chart_series_type); op(s, "theme", settings.theme); op(s, "sparkline_range", settings.sparkline_range); - op(s, "multiple_lines_bytes", settings.multiple_lines_bytes); + op(s, "multiple_lines_hex", settings.multiple_lines_hex); op(s, "log_livestream", settings.log_livestream); op(s, "log_path", settings.log_path); op(s, "drag_direction", (int &)settings.drag_direction); diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index 9f24a6fbd370f78..e75c519ac73e90c 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -33,7 +33,7 @@ class Settings : public QObject { int chart_series_type = 0; int theme = 0; int sparkline_range = 15; // 15 seconds - bool multiple_lines_bytes = true; + bool multiple_lines_hex = false; bool log_livestream = true; bool suppress_defined_signals = false; QString log_path; diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index b9795efedfa71b5..3abcf4d11128350 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -36,8 +36,8 @@ SignalModel::SignalModel(QObject *parent) : root(new Item), QAbstractItemModel(p 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", "Receiver Nodes", "Little Endian", "Signed", "Offset", "Factor", "Type", "Multiplex Value", "Extra Info", - "Unit", "Comment", "Minimum Value", "Maximum Value", "Value Descriptions"}; + QString titles[]{"Name", "Size", "Receiver Nodes", "Little Endian", "Signed", "Offset", "Factor", "Type", + "Multiplex Value", "Extra Info", "Unit", "Comment", "Minimum Value", "Maximum Value", "Value Table"}; 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)}); } @@ -68,10 +68,7 @@ void SignalModel::refresh() { } SignalModel::Item *SignalModel::getItem(const QModelIndex &index) const { - SignalModel::Item *item = nullptr; - if (index.isValid()) { - item = (SignalModel::Item *)index.internalPointer(); - } + auto item = index.isValid() ? (SignalModel::Item *)index.internalPointer() : nullptr; return item ? item : root.get(); } @@ -369,8 +366,7 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->setFont(label_font); QString freq = QString("%1 hz").arg(item->sparkline.freq(), 0, 'g', 2); painter->drawText(rect.adjusted(5, 0, 0, 0), Qt::AlignLeft | Qt::AlignVCenter, freq); - QFontMetrics fm(label_font); - value_adjust = fm.width(freq) + 10; + value_adjust = QFontMetrics(label_font).width(freq) + 10; } // signal value painter->setFont(option.font); @@ -622,13 +618,13 @@ void SignalView::handleSignalUpdated(const cabana::Signal *sig) { } } -void SignalView::updateState(const QHash *msgs) { +void SignalView::updateState(const std::set *msgs) { const auto &last_msg = can->lastMessage(model->msg_id); - if (model->rowCount() == 0 || (msgs && !msgs->contains(model->msg_id)) || last_msg.dat.size() == 0) return; + if (model->rowCount() == 0 || (msgs && !msgs->count(model->msg_id)) || last_msg.dat.size() == 0) return; for (auto item : model->root->children) { double value = 0; - if (item->sig->getValue((uint8_t *)last_msg.dat.constData(), last_msg.dat.size(), &value)) { + if (item->sig->getValue(last_msg.dat.data(), last_msg.dat.size(), &value)) { item->sig_val = item->sig->formatValue(value); } max_value_width = std::max(max_value_width, fontMetrics().width(item->sig_val)); diff --git a/tools/cabana/signalview.h b/tools/cabana/signalview.h index c08579bc5570566..30978f928cfc8e6 100644 --- a/tools/cabana/signalview.h +++ b/tools/cabana/signalview.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -82,7 +83,7 @@ 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; + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override; @@ -117,7 +118,7 @@ class SignalView : public QFrame { void setSparklineRange(int value); void handleSignalAdded(MessageId id, const cabana::Signal *sig); void handleSignalUpdated(const cabana::Signal *sig); - void updateState(const QHash *msgs = nullptr); + void updateState(const std::set *msgs = nullptr); struct TreeView : public QTreeView { TreeView(QWidget *parent) : QTreeView(parent) {} diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index eb2859e5a3d477a..c68259ed8b5dd44 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -1,8 +1,10 @@ #include "tools/cabana/streams/abstractstream.h" #include +#include -#include +#include "common/timing.h" +#include "tools/cabana/settings.h" static const int EVENT_NEXT_BUFFER_SIZE = 6 * 1024 * 1024; // 6MB @@ -15,82 +17,97 @@ StreamNotifier *StreamNotifier::instance() { AbstractStream::AbstractStream(QObject *parent) : QObject(parent) { assert(parent != nullptr); - new_msgs = std::make_unique>(); - event_buffer = std::make_unique(EVENT_NEXT_BUFFER_SIZE); + event_buffer_ = std::make_unique(EVENT_NEXT_BUFFER_SIZE); + QObject::connect(this, &AbstractStream::privateUpdateLastMsgsSignal, this, &AbstractStream::updateLastMessages, Qt::QueuedConnection); QObject::connect(this, &AbstractStream::seekedTo, this, &AbstractStream::updateLastMsgsTo); - QObject::connect(&settings, &Settings::changed, this, &AbstractStream::updateMasks); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &AbstractStream::updateMasks); QObject::connect(dbc(), &DBCManager::maskUpdated, this, &AbstractStream::updateMasks); QObject::connect(this, &AbstractStream::streamStarted, [this]() { emit StreamNotifier::instance()->changingStream(); delete can; can = this; - // TODO: add method stop() to class AbstractStream - QObject::connect(qApp, &QApplication::aboutToQuit, can, []() { - qDebug() << "stopping stream thread"; - can->pause(true); - }); emit StreamNotifier::instance()->streamStarted(); }); } void AbstractStream::updateMasks() { - std::lock_guard lk(mutex); - masks.clear(); - if (settings.suppress_defined_signals) { - for (auto s : sources) { - if (auto f = dbc()->findDBCFile(s)) { - for (const auto &[address, m] : f->getMessages()) { - masks[{.source = (uint8_t)s, .address = address}] = m.mask; - } + std::lock_guard lk(mutex_); + masks_.clear(); + if (!settings.suppress_defined_signals) + return; + + for (const auto s : sources) { + for (const auto &[address, m] : dbc()->getMessages(s)) { + masks_[{.source = (uint8_t)s, .address = address}] = m.mask; + } + } + // clear bit change counts + for (auto &[id, m] : messages_) { + auto &mask = masks_[id]; + const int size = std::min(mask.size(), m.last_changes.size()); + for (int i = 0; i < size; ++i) { + for (int j = 0; j < 8; ++j) { + if (((mask[i] >> (7 - j)) & 1) != 0) m.last_changes[i].bit_change_counts[j] = 0; + } + } + } +} + +void AbstractStream::suppressDefinedSignals(bool suppress) { + settings.suppress_defined_signals = suppress; + updateMasks(); +} + +size_t AbstractStream::suppressHighlighted() { + std::lock_guard lk(mutex_); + size_t cnt = 0; + const double cur_ts = currentSec(); + for (auto &[_, m] : messages_) { + for (auto &last_change : m.last_changes) { + const double dt = cur_ts - last_change.ts; + if (dt < 2.0) { + last_change.suppressed = true; } + // clear bit change counts + last_change.bit_change_counts.fill(0); + cnt += last_change.suppressed; } } + return cnt; +} + +void AbstractStream::clearSuppressed() { + std::lock_guard lk(mutex_); + for (auto &[_, m] : messages_) { + std::for_each(m.last_changes.begin(), m.last_changes.end(), [](auto &c) { c.suppressed = false; }); + } } -void AbstractStream::updateMessages(QHash *messages) { +void AbstractStream::updateLastMessages() { auto prev_src_size = sources.size(); auto prev_msg_size = last_msgs.size(); - for (auto it = messages->begin(); it != messages->end(); ++it) { - const auto &id = it.key(); - last_msgs[id] = it.value(); - sources.insert(id.source); + std::set msgs; + { + std::lock_guard lk(mutex_); + for (const auto &id : new_msgs_) { + last_msgs[id] = messages_[id]; + sources.insert(id.source); + } + msgs = std::move(new_msgs_); } + if (sources.size() != prev_src_size) { updateMasks(); emit sourcesUpdated(sources); } - emit updated(); - emit msgsReceived(messages, prev_msg_size != last_msgs.size()); - delete messages; - processing = false; + emit msgsReceived(&msgs, prev_msg_size != last_msgs.size()); } void AbstractStream::updateEvent(const MessageId &id, double sec, const uint8_t *data, uint8_t size) { - std::lock_guard lk(mutex); - auto mask_it = masks.find(id); - std::vector *mask = mask_it == masks.end() ? nullptr : &mask_it->second; - all_msgs[id].compute(id, (const char *)data, size, sec, getSpeed(), mask); - if (!new_msgs->contains(id)) { - new_msgs->insert(id, {}); - } -} - -bool AbstractStream::postEvents() { - // delay posting CAN message if UI thread is busy - if (processing == false) { - processing = true; - for (auto it = new_msgs->begin(); it != new_msgs->end(); ++it) { - it.value() = all_msgs[it.key()]; - } - // use pointer to avoid data copy in queued connection. - QMetaObject::invokeMethod(this, std::bind(&AbstractStream::updateMessages, this, new_msgs.release()), Qt::QueuedConnection); - new_msgs.reset(new QHash); - new_msgs->reserve(100); - return true; - } - return false; + std::lock_guard lk(mutex_); + messages_[id].compute(id, data, size, sec, getSpeed(), masks_[id]); + new_msgs_.insert(id); } const std::vector &AbstractStream::events(const MessageId &id) const { @@ -102,76 +119,62 @@ const std::vector &AbstractStream::events(const MessageId &id) const CanData &AbstractStream::lastMessage(const MessageId &id) { static CanData empty_data = {}; auto it = last_msgs.find(id); - return it != last_msgs.end() ? it.value() : empty_data; + return it != last_msgs.end() ? it->second : empty_data; } // it is thread safe to update data in updateLastMsgsTo. // updateLastMsgsTo is always called in UI thread. void AbstractStream::updateLastMsgsTo(double sec) { - new_msgs.reset(new QHash); - all_msgs.clear(); - last_msgs.clear(); + new_msgs_.clear(); + messages_.clear(); uint64_t last_ts = (sec + routeStartTime()) * 1e9; - for (auto &[id, ev] : events_) { - auto it = std::lower_bound(ev.crbegin(), ev.crend(), last_ts, [](auto e, uint64_t ts) { - return e->mono_time > ts; - }); - auto mask_it = masks.find(id); - std::vector *mask = mask_it == masks.end() ? nullptr : &mask_it->second; - if (it != ev.crend()) { - double ts = (*it)->mono_time / 1e9 - routeStartTime(); - auto &m = all_msgs[id]; - m.compute(id, (const char *)(*it)->dat, (*it)->size, ts, getSpeed(), mask); - m.count = std::distance(it, ev.crend()); + for (const auto &[id, ev] : events_) { + auto it = std::upper_bound(ev.begin(), ev.end(), last_ts, CompareCanEvent()); + if (it != ev.begin()) { + auto prev = std::prev(it); + double ts = (*prev)->mono_time / 1e9 - routeStartTime(); + auto &m = messages_[id]; + m.compute(id, (*prev)->dat, (*prev)->size, ts, getSpeed(), {}); + m.count = std::distance(ev.begin(), prev) + 1; } } - // deep copy all_msgs to last_msgs to avoid multi-threading issue. - last_msgs = all_msgs; - last_msgs.detach(); - // use a timer to prevent recursive calls - QTimer::singleShot(0, [this]() { - emit updated(); - emit msgsReceived(&last_msgs, true); - }); + bool id_changed = messages_.size() != last_msgs.size() || + std::any_of(messages_.cbegin(), messages_.cend(), + [this](const auto &m) { return !last_msgs.count(m.first); }); + last_msgs = messages_; + emit msgsReceived(nullptr, id_changed); } -void AbstractStream::mergeEvents(std::vector::const_iterator first, std::vector::const_iterator last) { - static MessageEventsMap msg_events; - static std::vector new_events; +const CanEvent *AbstractStream::newEvent(uint64_t mono_time, const cereal::CanData::Reader &c) { + auto dat = c.getDat(); + CanEvent *e = (CanEvent *)event_buffer_->allocate(sizeof(CanEvent) + sizeof(uint8_t) * dat.size()); + e->src = c.getSrc(); + e->address = c.getAddress(); + e->mono_time = mono_time; + e->size = dat.size(); + memcpy(e->dat, (uint8_t *)dat.begin(), e->size); + return e; +} +void AbstractStream::mergeEvents(const std::vector &events) { + static MessageEventsMap msg_events; std::for_each(msg_events.begin(), msg_events.end(), [](auto &e) { e.second.clear(); }); - new_events.clear(); - - for (auto it = first; it != last; ++it) { - if ((*it)->which == cereal::Event::Which::CAN) { - uint64_t ts = (*it)->mono_time; - for (const auto &c : (*it)->event.getCan()) { - auto dat = c.getDat(); - CanEvent *e = (CanEvent *)event_buffer->allocate(sizeof(CanEvent) + sizeof(uint8_t) * dat.size()); - e->src = c.getSrc(); - e->address = c.getAddress(); - e->mono_time = ts; - e->size = dat.size(); - memcpy(e->dat, (uint8_t *)dat.begin(), e->size); - - msg_events[{.source = e->src, .address = e->address}].push_back(e); - new_events.push_back(e); - } - } + for (auto e : events) { + msg_events[{.source = e->src, .address = e->address}].push_back(e); } - if (!new_events.empty()) { - for (auto &[id, new_e] : msg_events) { + if (!events.empty()) { + for (const auto &[id, new_e] : msg_events) { if (!new_e.empty()) { auto &e = events_[id]; auto pos = std::upper_bound(e.cbegin(), e.cend(), new_e.front()->mono_time, CompareCanEvent()); e.insert(pos, new_e.cbegin(), new_e.cend()); } } - auto pos = std::upper_bound(all_events_.cbegin(), all_events_.cend(), new_events.front()->mono_time, CompareCanEvent()); - all_events_.insert(pos, new_events.cbegin(), new_events.cend()); + auto pos = std::upper_bound(all_events_.cbegin(), all_events_.cend(), events.front()->mono_time, CompareCanEvent()); + all_events_.insert(pos, events.cbegin(), events.cend()); emit eventsMerged(msg_events); } lastest_event_ts = all_events_.empty() ? 0 : all_events_.back()->mono_time; @@ -181,15 +184,16 @@ void AbstractStream::mergeEvents(std::vector::const_iterator first, std namespace { -constexpr int periodic_threshold = 10; -constexpr int start_alpha = 128; -constexpr float fade_time = 2.0; -const QColor CYAN = QColor(0, 187, 255, start_alpha); -const QColor RED = QColor(255, 0, 0, start_alpha); -const QColor GREYISH_BLUE = QColor(102, 86, 169, start_alpha / 2); -const QColor CYAN_LIGHTER = QColor(0, 187, 255, start_alpha).lighter(135); -const QColor RED_LIGHTER = QColor(255, 0, 0, start_alpha).lighter(135); -const QColor GREYISH_BLUE_LIGHTER = QColor(102, 86, 169, start_alpha / 2).lighter(135); +enum Color { GREYISH_BLUE, CYAN, RED}; +QColor getColor(int c) { + constexpr int start_alpha = 128; + static const QColor colors[] = { + [GREYISH_BLUE] = QColor(102, 86, 169, start_alpha / 2), + [CYAN] = QColor(0, 187, 255, start_alpha), + [RED] = QColor(255, 0, 0, start_alpha), + }; + return settings.theme == LIGHT_THEME ? colors[c] : colors[c].lighter(135); +} inline QColor blend(const QColor &a, const QColor &b) { return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2, (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2); @@ -212,8 +216,8 @@ double calc_freq(const MessageId &msg_id, double current_sec) { } // namespace -void CanData::compute(const MessageId &msg_id, const char *can_data, const int size, double current_sec, - double playback_speed, const std::vector *mask, double in_freq) { +void CanData::compute(const MessageId &msg_id, const uint8_t *can_data, const int size, double current_sec, + double playback_speed, const std::vector &mask, double in_freq) { ts = current_sec; ++count; @@ -224,55 +228,53 @@ void CanData::compute(const MessageId &msg_id, const char *can_data, const int s if (dat.size() != size) { dat.resize(size); - bit_change_counts.resize(size); - colors = QVector(size, QColor(0, 0, 0, 0)); - last_change_t.assign(size, ts); - last_delta.resize(size); - same_delta_counter.resize(size); + colors.assign(size, QColor(0, 0, 0, 0)); + last_changes.resize(size); + std::for_each(last_changes.begin(), last_changes.end(), [current_sec](auto &c) { c.ts = current_sec; }); } else { - bool lighter = settings.theme == DARK_THEME; - const QColor &cyan = !lighter ? CYAN : CYAN_LIGHTER; - const QColor &red = !lighter ? RED : RED_LIGHTER; - const QColor &greyish_blue = !lighter ? GREYISH_BLUE : GREYISH_BLUE_LIGHTER; + constexpr int periodic_threshold = 10; + constexpr float fade_time = 2.0; + const float alpha_delta = 1.0 / (freq + 1) / (fade_time * playback_speed); for (int i = 0; i < size; ++i) { - const uint8_t mask_byte = (mask && i < mask->size()) ? (~((*mask)[i])) : 0xff; + auto &last_change = last_changes[i]; + + uint8_t mask_byte = last_change.suppressed ? 0x00 : 0xFF; + if (i < mask.size()) mask_byte &= ~(mask[i]); + const uint8_t last = dat[i] & mask_byte; const uint8_t cur = can_data[i] & mask_byte; - const int delta = cur - last; - if (last != cur) { - double delta_t = ts - last_change_t[i]; - + const int delta = cur - last; // Keep track if signal is changing randomly, or mostly moving in the same direction - if (std::signbit(delta) == std::signbit(last_delta[i])) { - same_delta_counter[i] = std::min(16, same_delta_counter[i] + 1); + if (std::signbit(delta) == std::signbit(last_change.delta)) { + last_change.same_delta_counter = std::min(16, last_change.same_delta_counter + 1); } else { - same_delta_counter[i] = std::max(0, same_delta_counter[i] - 4); + last_change.same_delta_counter = std::max(0, last_change.same_delta_counter - 4); } + const double delta_t = ts - last_change.ts; // Mostly moves in the same direction, color based on delta up/down - if (delta_t * freq > periodic_threshold || same_delta_counter[i] > 8) { + if (delta_t * freq > periodic_threshold || last_change.same_delta_counter > 8) { // Last change was while ago, choose color based on delta up or down - colors[i] = (cur > last) ? cyan : red; + colors[i] = getColor(cur > last ? CYAN : RED); } else { // Periodic changes - colors[i] = blend(colors[i], greyish_blue); + colors[i] = blend(colors[i], getColor(GREYISH_BLUE)); } // Track bit level changes const uint8_t tmp = (cur ^ last); for (int bit = 0; bit < 8; bit++) { - if (tmp & (1 << bit)) { - bit_change_counts[i][bit] += 1; + if (tmp & (1 << (7 - bit))) { + last_change.bit_change_counts[bit] += 1; } } - last_change_t[i] = ts; - last_delta[i] = delta; + last_change.ts = ts; + last_change.delta = delta; } else { // Fade out - float alpha_delta = 1.0 / (freq + 1) / (fade_time * playback_speed); colors[i].setAlphaF(std::max(0.0, colors[i].alphaF() - alpha_delta)); } } diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 02ebc4b5d180e7d..16d4040d624465d 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -1,34 +1,37 @@ #pragma once #include -#include #include +#include +#include #include #include #include #include -#include -#include "common/timing.h" +#include "cereal/messaging/messaging.h" #include "tools/cabana/dbc/dbcmanager.h" -#include "tools/cabana/settings.h" #include "tools/cabana/util.h" -#include "tools/replay/replay.h" struct CanData { - void compute(const MessageId &msg_id, const char *dat, const int size, double current_sec, - double playback_speed, const std::vector *mask = nullptr, double in_freq = 0); + void compute(const MessageId &msg_id, const uint8_t *dat, const int size, double current_sec, + double playback_speed, const std::vector &mask, double in_freq = 0); double ts = 0.; uint32_t count = 0; double freq = 0; - QByteArray dat; - QVector colors; - std::vector last_change_t; - std::vector> bit_change_counts; - std::vector last_delta; - std::vector same_delta_counter; + std::vector dat; + std::vector colors; + + struct ByteLastChange { + double ts; + int delta; + int same_delta_counter; + bool suppressed; + std::array bit_change_counts; + }; + std::vector last_changes; double last_freq_update_ts = 0; }; @@ -60,7 +63,7 @@ class AbstractStream : public QObject { AbstractStream(QObject *parent); virtual ~AbstractStream() {} virtual void start() = 0; - inline bool liveStreaming() const { return route() == nullptr; } + virtual bool liveStreaming() const { return true; } virtual void seekTo(double ts) {} virtual QString routeName() const = 0; virtual QString carFingerprint() const { return ""; } @@ -68,48 +71,57 @@ class AbstractStream : public QObject { virtual double routeStartTime() const { return 0; } virtual double currentSec() const = 0; virtual double totalSeconds() const { return lastEventMonoTime() / 1e9 - routeStartTime(); } - const CanData &lastMessage(const MessageId &id); - virtual const Route *route() const { return nullptr; } virtual void setSpeed(float speed) {} virtual double getSpeed() { return 1; } virtual bool isPaused() const { return false; } virtual void pause(bool pause) {} - const MessageEventsMap &eventsMap() const { return events_; } - const std::vector &allEvents() const { return all_events_; } + + inline const std::unordered_map &lastMessages() const { return last_msgs; } + inline const MessageEventsMap &eventsMap() const { return events_; } + inline const std::vector &allEvents() const { return all_events_; } + const CanData &lastMessage(const MessageId &id); const std::vector &events(const MessageId &id) const; + size_t suppressHighlighted(); + void clearSuppressed(); + void suppressDefinedSignals(bool suppress); + signals: void paused(); void resume(); void seekedTo(double sec); void streamStarted(); void eventsMerged(const MessageEventsMap &events_map); - void updated(); - void msgsReceived(const QHash *new_msgs, bool has_new_ids); + void msgsReceived(const std::set *new_msgs, bool has_new_ids); void sourcesUpdated(const SourceSet &s); + void privateUpdateLastMsgsSignal(); public: - QHash last_msgs; SourceSet sources; protected: - void mergeEvents(std::vector::const_iterator first, std::vector::const_iterator last); - bool postEvents(); - uint64_t lastEventMonoTime() const { return lastest_event_ts; } + void mergeEvents(const std::vector &events); + const CanEvent *newEvent(uint64_t mono_time, const cereal::CanData::Reader &c); void updateEvent(const MessageId &id, double sec, const uint8_t *data, uint8_t size); - void updateMessages(QHash *); - void updateMasks(); - void updateLastMsgsTo(double sec); + uint64_t lastEventMonoTime() const { return lastest_event_ts; } + std::vector all_events_; uint64_t lastest_event_ts = 0; - std::atomic processing = false; - std::unique_ptr> new_msgs; - QHash all_msgs; + +private: + void updateLastMessages(); + void updateLastMsgsTo(double sec); + void updateMasks(); + MessageEventsMap events_; - std::vector all_events_; - std::unique_ptr event_buffer; - std::mutex mutex; - std::unordered_map> masks; + std::unordered_map last_msgs; + std::unique_ptr event_buffer_; + + // Members accessed in multiple threads. (mutex protected) + std::mutex mutex_; + std::set new_msgs_; + std::unordered_map messages_; + std::unordered_map> masks_; }; class AbstractOpenStreamWidget : public QWidget { diff --git a/tools/cabana/streams/devicestream.cc b/tools/cabana/streams/devicestream.cc index 349a2d7a1cf73df..80507391a7d0856 100644 --- a/tools/cabana/streams/devicestream.cc +++ b/tools/cabana/streams/devicestream.cc @@ -8,6 +8,7 @@ #include #include #include +#include // DeviceStream @@ -21,17 +22,14 @@ void DeviceStream::streamThread() { 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); + std::unique_ptr msg(sock->receive(true)); if (!msg) { QThread::msleep(50); continue; } - - handleEvent(msg->getData(), msg->getSize()); - delete msg; + handleEvent(kj::ArrayPtr((capnp::word*)msg->getData(), msg->getSize() / sizeof(capnp::word))); } } diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index fd140eb8bf6f701..4e1f6d77d9f6ef2 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -1,12 +1,17 @@ #include "tools/cabana/streams/livestream.h" +#include #include +#include #include +#include "common/timing.h" +#include "common/util.h" + struct LiveStream::Logger { Logger() : start_ts(seconds_since_epoch()), segment_num(-1) {} - void write(const char *data, const size_t size) { + void write(kj::ArrayPtr data) { int n = (seconds_since_epoch() - start_ts) / 60.0; if (std::exchange(segment_num, n) != segment_num) { QString dir = QString("%1/%2--%3") @@ -17,7 +22,8 @@ struct LiveStream::Logger { fs.reset(new std::ofstream((dir + "/rlog").toStdString(), std::ios::binary | std::ios::out)); } - fs->write(data, size); + auto bytes = data.asBytes(); + fs->write((const char*)bytes.begin(), bytes.size()); } std::unique_ptr fs; @@ -57,14 +63,20 @@ LiveStream::~LiveStream() { } // called in streamThread -void LiveStream::handleEvent(const char *data, const size_t size) { +void LiveStream::handleEvent(kj::ArrayPtr data) { if (logger) { - logger->write(data, size); + logger->write(data); } - std::lock_guard lk(lock); - auto &msg = receivedMessages.emplace_back(data, size); - receivedEvents.push_back(msg.event); + capnp::FlatArrayMessageReader reader(data); + auto event = reader.getRoot(); + if (event.which() == cereal::Event::Which::CAN) { + const uint64_t mono_time = event.getLogMonoTime(); + std::lock_guard lk(lock); + for (const auto &c : event.getCan()) { + received_events_.push_back(newEvent(mono_time, c)); + } + } } void LiveStream::timerEvent(QTimerEvent *event) { @@ -72,9 +84,8 @@ void LiveStream::timerEvent(QTimerEvent *event) { { // merge events received from live stream thread. std::lock_guard lk(lock); - mergeEvents(receivedEvents.cbegin(), receivedEvents.cend()); - receivedEvents.clear(); - receivedMessages.clear(); + mergeEvents(received_events_); + received_events_.clear(); } if (!all_events_.empty()) { begin_event_ts = all_events_.front()->mono_time; @@ -112,7 +123,7 @@ void LiveStream::updateEvents() { updateEvent(id, (e->mono_time - begin_event_ts) / 1e9, e->dat, e->size); current_event_ts = e->mono_time; } - postEvents(); + emit privateUpdateLastMsgsSignal(); } void LiveStream::seekTo(double sec) { diff --git a/tools/cabana/streams/livestream.h b/tools/cabana/streams/livestream.h index d72112c6049dffd..719ea15c2476d07 100644 --- a/tools/cabana/streams/livestream.h +++ b/tools/cabana/streams/livestream.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -26,26 +25,16 @@ class LiveStream : public AbstractStream { protected: virtual void streamThread() = 0; - void handleEvent(const char *data, const size_t size); + void handleEvent(kj::ArrayPtr event); private: void startUpdateTimer(); void timerEvent(QTimerEvent *event) override; void updateEvents(); - struct Msg { - Msg(const char *data, const size_t size) { - event = ::new Event(aligned_buf.align(data, size)); - } - ~Msg() { ::delete event; } - Event *event; - AlignedBuffer aligned_buf; - }; - std::mutex lock; QThread *stream_thread; - std::vector receivedEvents; - std::deque receivedMessages; + std::vector received_events_; int timer_id; QBasicTimer update_timer; diff --git a/tools/cabana/streams/pandastream.cc b/tools/cabana/streams/pandastream.cc index 13d202d9cab3200..bea1fd7480bfc9d 100644 --- a/tools/cabana/streams/pandastream.cc +++ b/tools/cabana/streams/pandastream.cc @@ -1,15 +1,13 @@ #include "tools/cabana/streams/pandastream.h" -#include - +#include #include #include #include #include +#include #include -#include "selfdrive/ui/qt/util.h" - // TODO: remove clearLayout static void clearLayout(QLayout* layout) { while (layout->count() > 0) { @@ -90,7 +88,6 @@ void PandaStream::streamThread() { MessageBuilder msg; auto evt = msg.initEvent(); auto canData = evt.initCan(raw_can_data.size()); - for (uint i = 0; isend_heartbeat(false); } diff --git a/tools/cabana/streams/pandastream.h b/tools/cabana/streams/pandastream.h index 43803950f9eec3f..919156f400b632f 100644 --- a/tools/cabana/streams/pandastream.h +++ b/tools/cabana/streams/pandastream.h @@ -5,7 +5,6 @@ #include #include -#include #include "tools/cabana/streams/livestream.h" #include "selfdrive/boardd/panda.h" diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index ccf3e7ca0309350..e94aefec2b2e3d8 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -15,7 +15,7 @@ ReplayStream::ReplayStream(QObject *parent) : AbstractStream(parent) { op_prefix = std::make_unique(); #endif - QObject::connect(&settings, &Settings::changed, [this]() { + QObject::connect(&settings, &Settings::changed, this, [this]() { if (replay) replay->setSegmentCacheLimit(settings.max_cached_minutes); }); } @@ -28,8 +28,18 @@ void ReplayStream::mergeSegments() { for (auto &[n, seg] : replay->segments()) { if (seg && seg->isLoaded() && !processed_segments.count(n)) { processed_segments.insert(n); - const auto &events = seg->log->events; - mergeEvents(events.cbegin(), events.cend()); + + std::vector new_events; + new_events.reserve(seg->log->events.size()); + for (auto it = seg->log->events.cbegin(); it != seg->log->events.cend(); ++it) { + if ((*it)->which == cereal::Event::Which::CAN) { + const uint64_t ts = (*it)->mono_time; + for (const auto &c : (*it)->event.getCan()) { + new_events.push_back(newEvent(ts, c)); + } + } + } + mergeEvents(new_events); } } } @@ -52,7 +62,6 @@ void ReplayStream::start() { bool ReplayStream::eventFilter(const Event *event) { static double prev_update_ts = 0; - // delay posting CAN message if UI thread is busy if (event->which == cereal::Event::Which::CAN) { double current_sec = event->mono_time / 1e9 - routeStartTime(); for (const auto &c : event->event.getCan()) { @@ -64,9 +73,8 @@ bool ReplayStream::eventFilter(const Event *event) { double ts = millis_since_boot(); if ((ts - prev_update_ts) > (1000.0 / settings.fps)) { - if (postEvents()) { - prev_update_ts = ts; - } + emit privateUpdateLastMsgsSignal(); + prev_update_ts = ts; } return true; } diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index 7f8f8a4d3a5e032..95fb632628467cb 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -8,6 +8,7 @@ #include "common/prefix.h" #include "tools/cabana/streams/abstractstream.h" +#include "tools/replay/replay.h" class ReplayStream : public AbstractStream { Q_OBJECT @@ -18,13 +19,14 @@ class ReplayStream : public AbstractStream { 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 { replay->seekTo(std::max(double(0), ts), false); } + bool liveStreaming() const override { return false; } inline QString routeName() const override { return replay->route()->name(); } inline QString carFingerprint() const override { return replay->carFingerprint().c_str(); } double totalSeconds() const override { return replay->totalSeconds(); } inline QDateTime beginDateTime() const { return replay->route()->datetime(); } inline double routeStartTime() const override { return replay->routeStartTime() / (double)1e9; } inline double currentSec() const override { return replay->currentSeconds(); } - inline const Route *route() const override { return replay->route(); } + inline const Route *route() const { return replay->route(); } inline void setSpeed(float speed) override { replay->setSpeed(speed); } inline float getSpeed() const { return replay->getSpeed(); } inline Replay *getReplay() const { return replay.get(); } diff --git a/tools/cabana/streams/socketcanstream.cc b/tools/cabana/streams/socketcanstream.cc index 3df8e31f3bf9d5e..0f13b9901b3ad9d 100644 --- a/tools/cabana/streams/socketcanstream.cc +++ b/tools/cabana/streams/socketcanstream.cc @@ -1,8 +1,11 @@ #include "tools/cabana/streams/socketcanstream.h" -#include +#include +#include +#include #include #include +#include SocketCanStream::SocketCanStream(QObject *parent, SocketCanStreamConfig config_) : config(config_), LiveStream(parent) { if (!available()) { @@ -49,7 +52,6 @@ void SocketCanStream::streamThread() { auto evt = msg.initEvent(); auto canData = evt.initCan(frames.size()); - for (uint i = 0; i < frames.size(); i++) { if (!frames[i].isValid()) continue; @@ -60,8 +62,7 @@ void SocketCanStream::streamThread() { canData[i].setDat(kj::arrayPtr((uint8_t*)payload.data(), payload.size())); } - auto bytes = msg.toBytes(); - handleEvent((const char*)bytes.begin(), bytes.size()); + handleEvent(capnp::messageToFlatArray(msg)); } } diff --git a/tools/cabana/streams/socketcanstream.h b/tools/cabana/streams/socketcanstream.h index 6f2d7aa3539d299..e0fb826acb4c89d 100644 --- a/tools/cabana/streams/socketcanstream.h +++ b/tools/cabana/streams/socketcanstream.h @@ -5,10 +5,7 @@ #include #include #include - #include -#include -#include #include "tools/cabana/streams/livestream.h" @@ -21,7 +18,6 @@ class SocketCanStream : public LiveStream { public: SocketCanStream(QObject *parent, SocketCanStreamConfig config_ = {}); static AbstractOpenStreamWidget *widget(AbstractStream **stream); - static bool available(); inline QString routeName() const override { diff --git a/tools/cabana/streamselector.cc b/tools/cabana/streamselector.cc index 719ba72920bea5a..07755c0fe00c928 100644 --- a/tools/cabana/streamselector.cc +++ b/tools/cabana/streamselector.cc @@ -2,7 +2,6 @@ #include #include -#include #include #include diff --git a/tools/cabana/tools/findsignal.cc b/tools/cabana/tools/findsignal.cc index 51d86f596491cca..5155ad91d275fe2 100644 --- a/tools/cabana/tools/findsignal.cc +++ b/tools/cabana/tools/findsignal.cc @@ -192,7 +192,7 @@ void FindSignalDlg::search() { search_btn->setEnabled(false); stats_label->setVisible(false); search_btn->setText("Finding ...."); - QTimer::singleShot(0, [=]() { model->search(cmp); }); + QTimer::singleShot(0, this, [=]() { model->search(cmp); }); } void FindSignalDlg::setInitialSignals() { @@ -222,15 +222,15 @@ void FindSignalDlg::setInitialSignals() { } model->initial_signals.clear(); - for (auto it = can->last_msgs.cbegin(); it != can->last_msgs.cend(); ++it) { - if (buses.isEmpty() || buses.contains(it.key().source) && (addresses.isEmpty() || addresses.contains(it.key().address))) { - const auto &events = can->events(it.key()); + for (const auto &[id, m] : can->lastMessages()) { + if (buses.isEmpty() || buses.contains(id.source) && (addresses.isEmpty() || addresses.contains(id.address))) { + const auto &events = can->events(id); auto e = std::lower_bound(events.cbegin(), events.cend(), first_time, CompareCanEvent()); if (e != events.cend()) { - const int total_size = it.value().dat.size() * 8; + const int total_size = m.dat.size() * 8; for (int size = min_size->value(); size <= max_size->value(); ++size) { for (int start = 0; start <= total_size - size; ++start) { - FindSignalModel::SearchSignal s{.id = it.key(), .mono_time = first_time, .sig = sig}; + FindSignalModel::SearchSignal s{.id = id, .mono_time = first_time, .sig = sig}; s.sig.start_bit = start; s.sig.size = size; updateMsbLsb(s.sig); diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 38190da3014559d..f984230c47074f4 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include @@ -59,23 +59,18 @@ MessageBytesDelegate::MessageBytesDelegate(QObject *parent, bool multiple_lines) hex_text_table[i].setText(QStringLiteral("%1").arg(i, 2, 16, QLatin1Char('0')).toUpper()); hex_text_table[i].prepare({}, fixed_font); } + h_margin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; + v_margin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameVMargin) + 1; } -int MessageBytesDelegate::widthForBytes(int n) const { - int h_margin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; - return n * byte_size.width() + h_margin * 2; +QSize MessageBytesDelegate::sizeForBytes(int n) const { + int rows = multiple_lines ? std::max(1, n / 8) : 1; + return {(n / rows) * byte_size.width() + h_margin * 2, rows * byte_size.height() + v_margin * 2}; } QSize MessageBytesDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { - int v_margin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameVMargin) + 1; auto data = index.data(BytesRole); - if (!data.isValid()) { - return {1, byte_size.height() + 2 * v_margin}; - } - int n = data.toByteArray().size(); - assert(n >= 0 && n <= 64); - return !multiple_lines ? QSize{widthForBytes(n), byte_size.height() + 2 * v_margin} - : QSize{widthForBytes(8), byte_size.height() * std::max(1, n / 8) + 2 * v_margin}; + return sizeForBytes(data.isValid() ? static_cast *>(data.value())->size() : 0); } void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { @@ -84,20 +79,17 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & return QStyledItemDelegate::paint(painter, option, index); } - auto byte_list = data.toByteArray(); - auto colors = index.data(ColorsRole).value>(); - - int v_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin); - int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin); + QFont old_font = painter->font(); + QPen old_pen = painter->pen(); if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.brush(QPalette::Normal, QPalette::Highlight)); } - const QPoint pt{option.rect.left() + h_margin, option.rect.top() + v_margin}; - QFont old_font = painter->font(); - QPen old_pen = painter->pen(); painter->setFont(fixed_font); - for (int i = 0; i < byte_list.size(); ++i) { + + const auto &bytes = *static_cast*>(data.value()); + const auto &colors = *static_cast*>(index.data(ColorsRole).value()); + for (int i = 0; i < bytes.size(); ++i) { int row = !multiple_lines ? 0 : i / 8; int column = !multiple_lines ? i : i % 8; QRect r = QRect({pt.x() + column * byte_size.width(), pt.y() + row * byte_size.height()}, byte_size); @@ -110,7 +102,7 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & } else if (option.state & QStyle::State_Selected) { painter->setPen(option.palette.color(QPalette::HighlightedText)); } - utils::drawStaticText(painter, r, hex_text_table[(uint8_t)(byte_list[i])]); + utils::drawStaticText(painter, r, hex_text_table[bytes[i]]); } painter->setFont(old_font); painter->setPen(old_pen); @@ -251,15 +243,6 @@ QString formatSeconds(double sec, bool include_milliseconds, bool absolute_time) } // namespace utils -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]; -} - int num_decimals(double num) { const QString string = QString::number(num); auto dot_pos = string.indexOf('.'); diff --git a/tools/cabana/util.h b/tools/cabana/util.h index da476ab31a0ad74..158321f7842964e 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -18,7 +17,6 @@ #include #include #include -#include #include "tools/cabana/dbc/dbc.h" #include "tools/cabana/settings.h" @@ -75,18 +73,16 @@ class MessageBytesDelegate : public QStyledItemDelegate { QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; bool multipleLines() const { return multiple_lines; } void setMultipleLines(bool v) { multiple_lines = v; } - int widthForBytes(int n) const; + QSize sizeForBytes(int n) const; private: std::array hex_text_table; QFont fixed_font; QSize byte_size = {}; bool multiple_lines = false; + int h_margin, v_margin; }; -inline QString toHex(const QByteArray &dat) { return dat.toHex(' ').toUpper(); } -QString toHex(uint8_t byte); - class NameValidator : public QRegExpValidator { Q_OBJECT public: @@ -108,6 +104,10 @@ inline void drawStaticText(QPainter *p, const QRect &r, const QStaticText &text) auto size = (r.size() - text.size()) / 2; p->drawStaticText(r.left() + size.width(), r.top() + size.height(), text); } +inline QString toHex(const std::vector &dat, char separator = '\0') { + return QByteArray::fromRawData((const char *)dat.data(), dat.size()).toHex(separator).toUpper(); +} + } class ToolButton : public QToolButton { diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 7afcc7b9385ee89..bbb1ef28daf7960 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -13,6 +13,9 @@ #include #include +#include "tools/cabana/streams/replaystream.h" +#include "tools/cabana/util.h" + const int MIN_VIDEO_HEIGHT = 100; const int THUMBNAIL_MARGIN = 3; @@ -35,7 +38,7 @@ VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) { setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); QObject::connect(can, &AbstractStream::paused, this, &VideoWidget::updatePlayBtnState); QObject::connect(can, &AbstractStream::resume, this, &VideoWidget::updatePlayBtnState); - QObject::connect(can, &AbstractStream::updated, this, &VideoWidget::updateState); + QObject::connect(can, &AbstractStream::msgsReceived, this, &VideoWidget::updateState); updatePlayBtnState(); setWhatsThis(tr(R"( @@ -179,6 +182,8 @@ void VideoWidget::vipcAvailableStreamsUpdated(std::set streams void VideoWidget::loopPlaybackClicked() { auto replay = qobject_cast(can)->getReplay(); + if (!replay) return; + if (replay->hasFlag(REPLAY_FLAG_NO_LOOP)) { replay->removeFlag(REPLAY_FLAG_NO_LOOP); loop_btn->setIcon("repeat"); diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index c2fdb41df817058..69f1edd2bc60728 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -5,12 +5,14 @@ #include #include +#include #include #include #include #include "selfdrive/ui/qt/widgets/cameraview.h" -#include "tools/cabana/streams/replaystream.h" +#include "tools/cabana/util.h" +#include "tools/replay/logreader.h" struct AlertInfo { cereal::ControlsState::AlertStatus status; From 57c8304c2562e807d5b95d0edd78636de215e526 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 30 Oct 2023 09:58:57 -0700 Subject: [PATCH 065/133] jenkins: retry on failed git checkouts (#30345) * jenkins: retry on failed git checkouts * test * Revert "test" This reverts commit ea57ba025630eb3105a9ccdce3bdc17f72678c72. --- Jenkinsfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 35c16e29c94d82c..314170341ecbf4e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -64,7 +64,9 @@ def deviceStage(String stageName, String deviceType, List env, def steps) { docker.image('ghcr.io/commaai/alpine-ssh').inside('--user=root') { lock(resource: "", label: deviceType, inversePrecedence: true, variable: 'device_ip', quantity: 1) { timeout(time: 20, unit: 'MINUTES') { - device(device_ip, "git checkout", extra + "\n" + readFile("selfdrive/test/setup_device_ci.sh")) + retry (3) { + device(device_ip, "git checkout", extra + "\n" + readFile("selfdrive/test/setup_device_ci.sh")) + } steps.each { item -> device(device_ip, item[0], item[1]) } From d67276a45d8bfff3a013915e0ad861bd04c71f1d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 30 Oct 2023 13:08:43 -0700 Subject: [PATCH 066/133] bump panda (#30346) --- SConstruct | 4 ++++ panda | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/SConstruct b/SConstruct index c0f1a070b258a2f..b96347d9b2bac90 100644 --- a/SConstruct +++ b/SConstruct @@ -26,6 +26,10 @@ AddOption('--ubsan', action='store_true', help='turn on UBSan') +AddOption('--coverage', + action='store_true', + help='build with test coverage options') + AddOption('--clazy', action='store_true', help='build with clazy') diff --git a/panda b/panda index 549fa32fc7b0354..f3bdfdd4354ccc3 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 549fa32fc7b0354ebbb48bae846bff380eab9446 +Subproject commit f3bdfdd4354ccc3a512dc289dc038d5b30d1fec2 From 7a5d85232fee1b4792f1bfcfcea38a2f57c0b0ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Mon, 30 Oct 2023 15:17:32 -0700 Subject: [PATCH 067/133] regen: dummy dcamera support (#30323) * DummyFrameReader * dummy_dcam_if_missing flag * Blank dcamera for all neo segments, as dmonitoringd does not support neo camera feeds * Remove trailing whitespace * zero_dcamera staticmethod * enable dmonitoring in test_regen * Simplify. User decides wether to use dummy or not * Moving some stuff * rename to dummy_driver_cam --- selfdrive/test/process_replay/regen.py | 53 +++++++++++++++++---- selfdrive/test/process_replay/regen_all.py | 2 +- selfdrive/test/process_replay/test_regen.py | 11 ++--- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/selfdrive/test/process_replay/regen.py b/selfdrive/test/process_replay/regen.py index 5024ecaee80a4e8..245b5b2709e14a0 100755 --- a/selfdrive/test/process_replay/regen.py +++ b/selfdrive/test/process_replay/regen.py @@ -3,18 +3,42 @@ import argparse import time import capnp +import numpy as np from typing import Union, Iterable, Optional, List, Any, Dict, Tuple from openpilot.selfdrive.test.process_replay.process_replay import CONFIGS, FAKEDATA, ProcessConfig, replay_process, get_process_config, \ check_openpilot_enabled, get_custom_params_from_lr +from openpilot.selfdrive.test.process_replay.vision_meta import DRIVER_FRAME_SIZES from openpilot.selfdrive.test.update_ci_routes import upload_route from openpilot.tools.lib.route import Route -from openpilot.tools.lib.framereader import FrameReader +from openpilot.tools.lib.framereader import FrameReader, BaseFrameReader, FrameType from openpilot.tools.lib.logreader import LogReader, LogIterable from openpilot.tools.lib.helpers import save_log +class DummyFrameReader(BaseFrameReader): + def __init__(self, w: int, h: int, frame_count: int, pix_val: int): + self.pix_val = pix_val + self.w, self.h = w, h + self.frame_count = frame_count + self.frame_type = FrameType.raw + + def get(self, idx, count=1, pix_fmt="yuv420p"): + if pix_fmt == "rgb24": + shape = (self.h, self.w, 3) + elif pix_fmt == "nv12" or pix_fmt == "yuv420p": + shape = (int((self.h * self.w) * 3 / 2),) + else: + raise NotImplementedError + + return [np.full(shape, self.pix_val, dtype=np.uint8) for _ in range(count)] + + @staticmethod + def zero_dcamera(): + return DummyFrameReader(*DRIVER_FRAME_SIZES["tici"], 1200, 0) + + def regen_segment( lr: LogIterable, frs: Optional[Dict[str, Any]] = None, processes: Iterable[ProcessConfig] = CONFIGS, disable_tqdm: bool = False @@ -31,7 +55,8 @@ def regen_segment( def setup_data_readers( - route: str, sidx: int, use_route_meta: bool, needs_driver_cam: bool = True, needs_road_cam: bool = True + route: str, sidx: int, use_route_meta: bool, + needs_driver_cam: bool = True, needs_road_cam: bool = True, dummy_driver_cam: bool = False ) -> Tuple[LogReader, Dict[str, Any]]: if use_route_meta: r = Route(route) @@ -41,8 +66,13 @@ def setup_data_readers( frs['roadCameraState'] = FrameReader(r.camera_paths()[sidx]) if needs_road_cam and len(r.ecamera_paths()) > sidx and r.ecamera_paths()[sidx] is not None: frs['wideRoadCameraState'] = FrameReader(r.ecamera_paths()[sidx]) - if needs_driver_cam and len(r.dcamera_paths()) > sidx and r.dcamera_paths()[sidx] is not None: - frs['driverCameraState'] = FrameReader(r.dcamera_paths()[sidx]) + if needs_driver_cam: + if dummy_driver_cam: + frs['driverCameraState'] = DummyFrameReader.zero_dcamera() + elif len(r.dcamera_paths()) > sidx and r.dcamera_paths()[sidx] is not None: + device_type = next(str(msg.initData.deviceType) for msg in lr if msg.which() == "initData") + assert device_type != "neo", "Driver camera not supported on neo segments. Use dummy dcamera." + frs['driverCameraState'] = FrameReader(r.dcamera_paths()[sidx]) else: lr = LogReader(f"cd:/{route.replace('|', '/')}/{sidx}/rlog.bz2") frs = {} @@ -51,14 +81,19 @@ def setup_data_readers( if next((True for m in lr if m.which() == "wideRoadCameraState"), False): frs['wideRoadCameraState'] = FrameReader(f"cd:/{route.replace('|', '/')}/{sidx}/ecamera.hevc") if needs_driver_cam: - frs['driverCameraState'] = FrameReader(f"cd:/{route.replace('|', '/')}/{sidx}/dcamera.hevc") + if dummy_driver_cam: + frs['driverCameraState'] = DummyFrameReader.zero_dcamera() + else: + device_type = next(str(msg.initData.deviceType) for msg in lr if msg.which() == "initData") + assert device_type != "neo", "Driver camera not supported on neo segments. Use dummy dcamera." + frs['driverCameraState'] = FrameReader(f"cd:/{route.replace('|', '/')}/{sidx}/dcamera.hevc") return lr, frs def regen_and_save( route: str, sidx: int, processes: Union[str, Iterable[str]] = "all", outdir: str = FAKEDATA, - upload: bool = False, use_route_meta: bool = False, disable_tqdm: bool = False + upload: bool = False, use_route_meta: bool = False, disable_tqdm: bool = False, dummy_driver_cam: bool = False ) -> str: if not isinstance(processes, str) and not hasattr(processes, "__iter__"): raise ValueError("whitelist_proc must be a string or iterable") @@ -77,7 +112,8 @@ def regen_and_save( all_vision_pubs = {pub for cfg in replayed_processes for pub in cfg.vision_pubs} lr, frs = setup_data_readers(route, sidx, use_route_meta, needs_driver_cam="driverCameraState" in all_vision_pubs, - needs_road_cam="roadCameraState" in all_vision_pubs or "wideRoadCameraState" in all_vision_pubs) + needs_road_cam="roadCameraState" in all_vision_pubs or "wideRoadCameraState" in all_vision_pubs, + dummy_driver_cam=dummy_driver_cam) output_logs = regen_segment(lr, frs, replayed_processes, disable_tqdm=disable_tqdm) log_dir = os.path.join(outdir, time.strftime("%Y-%m-%d--%H-%M-%S--0", time.gmtime())) @@ -107,6 +143,7 @@ def comma_separated_list(string): parser = argparse.ArgumentParser(description="Generate new segments from old ones") parser.add_argument("--upload", action="store_true", help="Upload the new segment to the CI bucket") parser.add_argument("--outdir", help="log output dir", default=FAKEDATA) + parser.add_argument("--dummy-dcamera", action='store_true', help="Use dummy blank driver camera") parser.add_argument("--whitelist-procs", type=comma_separated_list, default=all_procs, help="Comma-separated whitelist of processes to regen (e.g. controlsd,radard)") parser.add_argument("--blacklist-procs", type=comma_separated_list, default=[], @@ -117,4 +154,4 @@ def comma_separated_list(string): blacklist_set = set(args.blacklist_procs) processes = [p for p in args.whitelist_procs if p not in blacklist_set] - regen_and_save(args.route, args.seg, processes=processes, upload=args.upload, outdir=args.outdir) + regen_and_save(args.route, args.seg, processes=processes, upload=args.upload, outdir=args.outdir, dummy_driver_cam=args.dummy_dcamera) diff --git a/selfdrive/test/process_replay/regen_all.py b/selfdrive/test/process_replay/regen_all.py index b797b9b0da05bfd..656a5b89e1368ac 100755 --- a/selfdrive/test/process_replay/regen_all.py +++ b/selfdrive/test/process_replay/regen_all.py @@ -18,7 +18,7 @@ def regen_job(segment, upload, disable_tqdm): fake_dongle_id = 'regen' + ''.join(random.choice('0123456789ABCDEF') for _ in range(11)) try: relr = regen_and_save(sn.route_name.canonical_name, sn.segment_num, upload=upload, use_route_meta=False, - outdir=os.path.join(FAKEDATA, fake_dongle_id), disable_tqdm=disable_tqdm) + outdir=os.path.join(FAKEDATA, fake_dongle_id), disable_tqdm=disable_tqdm, dummy_driver_cam=True) relr = '|'.join(relr.split('/')[-2:]) return f' ("{segment[0]}", "{relr}"), ' except Exception as e: diff --git a/selfdrive/test/process_replay/test_regen.py b/selfdrive/test/process_replay/test_regen.py index ec1277a76c778bb..f35220556489cd4 100755 --- a/selfdrive/test/process_replay/test_regen.py +++ b/selfdrive/test/process_replay/test_regen.py @@ -4,13 +4,12 @@ from parameterized import parameterized -from openpilot.selfdrive.test.process_replay.regen import regen_segment -from openpilot.selfdrive.test.process_replay.process_replay import check_openpilot_enabled, CONFIGS +from openpilot.selfdrive.test.process_replay.regen import regen_segment, DummyFrameReader +from openpilot.selfdrive.test.process_replay.process_replay import check_openpilot_enabled from openpilot.selfdrive.test.openpilotci import get_url from openpilot.tools.lib.logreader import LogReader from openpilot.tools.lib.framereader import FrameReader -EXCLUDED_PROCESSES = {"dmonitoringd", "dmonitoringmodeld"} TESTED_SEGMENTS = [ ("PRIUS_C2", "0982d79ebb0de295|2021-01-04--17-13-21--13"), # TOYOTA PRIUS 2017: NEO, pandaStateDEPRECATED, no peripheralState, sensorEventsDEPRECATED # Enable these once regen on CI becomes faster or use them for different tests running controlsd in isolation @@ -21,9 +20,9 @@ def ci_setup_data_readers(route, sidx): lr = LogReader(get_url(route, sidx, "rlog")) - # dm disabled frs = { 'roadCameraState': FrameReader(get_url(route, sidx, "fcamera")), + 'driverCameraState': DummyFrameReader.zero_dcamera() } if next((True for m in lr if m.which() == "wideRoadCameraState"), False): frs["wideRoadCameraState"] = FrameReader(get_url(route, sidx, "ecamera")) @@ -34,11 +33,9 @@ def ci_setup_data_readers(route, sidx): class TestRegen(unittest.TestCase): @parameterized.expand(TESTED_SEGMENTS) def test_engaged(self, case_name, segment): - tested_procs = [p for p in CONFIGS if p.proc_name not in EXCLUDED_PROCESSES] - route, sidx = segment.rsplit("--", 1) lr, frs = ci_setup_data_readers(route, sidx) - output_logs = regen_segment(lr, frs, processes=tested_procs, disable_tqdm=True) + output_logs = regen_segment(lr, frs, disable_tqdm=True) engaged = check_openpilot_enabled(output_logs) self.assertTrue(engaged, f"openpilot not engaged in {case_name}") From e5eea7276f82f0e8467c43e52545ca06701526fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Mon, 30 Oct 2023 15:33:17 -0700 Subject: [PATCH 068/133] regen: update refs with dummy dcamera (#30347) Update refs --- selfdrive/test/process_replay/ref_commit | 2 +- .../test/process_replay/test_processes.py | 34 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 7f484d26589c690..de54ba6e90ef13d 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -d05b67ec66630521e8cedb90981002d57d738f6d +6e27d5c97fe6554a86e9ee8bb9259e0cc6df5bb1 \ 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 c3321208b66da92..2baeaa8e52c9331 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -41,23 +41,23 @@ ] segments = [ - ("BODY", "aregenECF15D9E559|2023-05-10--14-26-40--0"), - ("HYUNDAI", "aregenAB9F543F70A|2023-05-10--14-28-25--0"), - ("HYUNDAI2", "aregen39F5A028F96|2023-05-10--14-31-00--0"), - ("TOYOTA", "aregen8D6A8B36E8D|2023-05-10--14-32-38--0"), - ("TOYOTA2", "aregenB1933C49809|2023-05-10--14-34-14--0"), - ("TOYOTA3", "aregen5D9915223DC|2023-05-10--14-36-43--0"), - ("HONDA", "aregen484B732B675|2023-05-10--14-38-23--0"), - ("HONDA2", "aregenAF6ACED4713|2023-05-10--14-40-01--0"), - ("CHRYSLER", "aregen99B094E1E2E|2023-05-10--14-41-40--0"), - ("RAM", "aregen5C2487E1EEB|2023-05-10--14-44-09--0"), - ("SUBARU", "aregen98D277B792E|2023-05-10--14-46-46--0"), - ("GM", "aregen377BA28D848|2023-05-10--14-48-28--0"), - ("GM2", "aregen7CA0CC0F0C2|2023-05-10--14-51-00--0"), - ("NISSAN", "aregen7097BF01563|2023-05-10--14-52-43--0"), - ("VOLKSWAGEN", "aregen765AF3D2CB5|2023-05-10--14-54-23--0"), - ("MAZDA", "aregen3053762FF2E|2023-05-10--14-56-53--0"), - ("FORD", "aregenDDE0F89FA1E|2023-05-10--14-59-26--0"), + ("BODY", "regen7FE9F3C7CE3|2023-10-25--23-56-32--0"), + ("HYUNDAI", "regen7519EF9EE71|2023-10-25--23-53-59--0"), + ("HYUNDAI2", "regenF68B9F1B286|2023-10-25--23-56-31--0"), + ("TOYOTA", "regen56DC072FA51|2023-10-25--23-53-51--0"), + ("TOYOTA2", "regen78130056536|2023-10-25--23-53-58--0"), + ("TOYOTA3", "regenC554B250909|2023-10-25--23-58-53--0"), + ("HONDA", "regen3ED625586FB|2023-10-25--23-56-29--0"), + ("HONDA2", "regen9F1A8F44FD5|2023-10-25--23-56-34--0"), + ("CHRYSLER", "regen60CE93181EA|2023-10-25--23-59-01--0"), + ("RAM", "regen9E2B62E8E9A|2023-10-26--00-00-41--0"), + ("SUBARU", "regenEEBF379E0ED|2023-10-26--00-01-37--0"), + ("GM", "regen0B0EE5D6E0D|2023-10-25--23-58-57--0"), + ("GM2", "regen043B44E4FBD|2023-10-26--00-03-51--0"), + ("NISSAN", "regen14F35E327BC|2023-10-26--00-01-22--0"), + ("VOLKSWAGEN", "regen63A052AE7D7|2023-10-26--00-01-36--0"), + ("MAZDA", "regenF9047685121|2023-10-26--00-05-02--0"), + ("FORD", "regen5115F2AE4FE|2023-10-26--00-06-17--0"), ] # dashcamOnly makes don't need to be tested until a full port is done From c04e019af4e3789541493083391ef88cc4b702d2 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 31 Oct 2023 11:31:57 -0700 Subject: [PATCH 069/133] Update Python packages and pre-commit hooks (#30352) Co-authored-by: adeebshihadeh --- .pre-commit-config.yaml | 2 +- poetry.lock | 377 ++++++++++++++++++++-------------------- 2 files changed, 187 insertions(+), 192 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 880912e2712fd5f..6d99120bd090100 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -41,7 +41,7 @@ repos: args: ['--explicit-package-bases'] exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)' - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.1 + rev: v0.1.3 hooks: - id: ruff exclude: '^(third_party/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)' diff --git a/poetry.lock b/poetry.lock index a4e47d2359434de..bfd4491d6b2ef8f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -333,19 +333,19 @@ aio = ["aiohttp (>=3.0)"] [[package]] name = "azure-identity" -version = "1.14.1" +version = "1.15.0" description = "Microsoft Azure Identity Library for Python" optional = false python-versions = ">=3.7" files = [ - {file = "azure-identity-1.14.1.zip", hash = "sha256:48e2a9dbdc59b4f095f841d867d9a8cbe4c1cdbbad8251e055561afd47b4a9b8"}, - {file = "azure_identity-1.14.1-py3-none-any.whl", hash = "sha256:3a5bef8e9c3281e864e869739be8d67424bff616cddae96b546ca2a5168d863d"}, + {file = "azure-identity-1.15.0.tar.gz", hash = "sha256:4c28fc246b7f9265610eb5261d65931183d019a23d4b0e99357facb2e6c227c8"}, + {file = "azure_identity-1.15.0-py3-none-any.whl", hash = "sha256:a14b1f01c7036f11f148f22cd8c16e05035293d714458d6b44ddf534d93eb912"}, ] [package.dependencies] -azure-core = ">=1.11.0,<2.0.0" +azure-core = ">=1.23.0,<2.0.0" cryptography = ">=2.5" -msal = ">=1.20.0,<2.0.0" +msal = ">=1.24.0,<2.0.0" msal-extensions = ">=0.3.0,<2.0.0" [[package]] @@ -906,34 +906,34 @@ files = [ [[package]] name = "cryptography" -version = "41.0.4" +version = "41.0.5" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-41.0.4-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:80907d3faa55dc5434a16579952ac6da800935cd98d14dbd62f6f042c7f5e839"}, - {file = "cryptography-41.0.4-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:35c00f637cd0b9d5b6c6bd11b6c3359194a8eba9c46d4e875a3660e3b400005f"}, - {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cecfefa17042941f94ab54f769c8ce0fe14beff2694e9ac684176a2535bf9714"}, - {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e40211b4923ba5a6dc9769eab704bdb3fbb58d56c5b336d30996c24fcf12aadb"}, - {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:23a25c09dfd0d9f28da2352503b23e086f8e78096b9fd585d1d14eca01613e13"}, - {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2ed09183922d66c4ec5fdaa59b4d14e105c084dd0febd27452de8f6f74704143"}, - {file = "cryptography-41.0.4-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5a0f09cefded00e648a127048119f77bc2b2ec61e736660b5789e638f43cc397"}, - {file = "cryptography-41.0.4-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:9eeb77214afae972a00dee47382d2591abe77bdae166bda672fb1e24702a3860"}, - {file = "cryptography-41.0.4-cp37-abi3-win32.whl", hash = "sha256:3b224890962a2d7b57cf5eeb16ccaafba6083f7b811829f00476309bce2fe0fd"}, - {file = "cryptography-41.0.4-cp37-abi3-win_amd64.whl", hash = "sha256:c880eba5175f4307129784eca96f4e70b88e57aa3f680aeba3bab0e980b0f37d"}, - {file = "cryptography-41.0.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:004b6ccc95943f6a9ad3142cfabcc769d7ee38a3f60fb0dddbfb431f818c3a67"}, - {file = "cryptography-41.0.4-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:86defa8d248c3fa029da68ce61fe735432b047e32179883bdb1e79ed9bb8195e"}, - {file = "cryptography-41.0.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:37480760ae08065437e6573d14be973112c9e6dcaf5f11d00147ee74f37a3829"}, - {file = "cryptography-41.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b5f4dfe950ff0479f1f00eda09c18798d4f49b98f4e2006d644b3301682ebdca"}, - {file = "cryptography-41.0.4-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7e53db173370dea832190870e975a1e09c86a879b613948f09eb49324218c14d"}, - {file = "cryptography-41.0.4-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5b72205a360f3b6176485a333256b9bcd48700fc755fef51c8e7e67c4b63e3ac"}, - {file = "cryptography-41.0.4-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:93530900d14c37a46ce3d6c9e6fd35dbe5f5601bf6b3a5c325c7bffc030344d9"}, - {file = "cryptography-41.0.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efc8ad4e6fc4f1752ebfb58aefece8b4e3c4cae940b0994d43649bdfce8d0d4f"}, - {file = "cryptography-41.0.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3391bd8e6de35f6f1140e50aaeb3e2b3d6a9012536ca23ab0d9c35ec18c8a91"}, - {file = "cryptography-41.0.4-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0d9409894f495d465fe6fda92cb70e8323e9648af912d5b9141d616df40a87b8"}, - {file = "cryptography-41.0.4-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8ac4f9ead4bbd0bc8ab2d318f97d85147167a488be0e08814a37eb2f439d5cf6"}, - {file = "cryptography-41.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:047c4603aeb4bbd8db2756e38f5b8bd7e94318c047cfe4efeb5d715e08b49311"}, - {file = "cryptography-41.0.4.tar.gz", hash = "sha256:7febc3094125fc126a7f6fb1f420d0da639f3f32cb15c8ff0dc3997c4549f51a"}, + {file = "cryptography-41.0.5-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:da6a0ff8f1016ccc7477e6339e1d50ce5f59b88905585f77193ebd5068f1e797"}, + {file = "cryptography-41.0.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:b948e09fe5fb18517d99994184854ebd50b57248736fd4c720ad540560174ec5"}, + {file = "cryptography-41.0.5-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d38e6031e113b7421db1de0c1b1f7739564a88f1684c6b89234fbf6c11b75147"}, + {file = "cryptography-41.0.5-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e270c04f4d9b5671ebcc792b3ba5d4488bf7c42c3c241a3748e2599776f29696"}, + {file = "cryptography-41.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ec3b055ff8f1dce8e6ef28f626e0972981475173d7973d63f271b29c8a2897da"}, + {file = "cryptography-41.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7d208c21e47940369accfc9e85f0de7693d9a5d843c2509b3846b2db170dfd20"}, + {file = "cryptography-41.0.5-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8254962e6ba1f4d2090c44daf50a547cd5f0bf446dc658a8e5f8156cae0d8548"}, + {file = "cryptography-41.0.5-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a48e74dad1fb349f3dc1d449ed88e0017d792997a7ad2ec9587ed17405667e6d"}, + {file = "cryptography-41.0.5-cp37-abi3-win32.whl", hash = "sha256:d3977f0e276f6f5bf245c403156673db103283266601405376f075c849a0b936"}, + {file = "cryptography-41.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:73801ac9736741f220e20435f84ecec75ed70eda90f781a148f1bad546963d81"}, + {file = "cryptography-41.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3be3ca726e1572517d2bef99a818378bbcf7d7799d5372a46c79c29eb8d166c1"}, + {file = "cryptography-41.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e886098619d3815e0ad5790c973afeee2c0e6e04b4da90b88e6bd06e2a0b1b72"}, + {file = "cryptography-41.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:573eb7128cbca75f9157dcde974781209463ce56b5804983e11a1c462f0f4e88"}, + {file = "cryptography-41.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0c327cac00f082013c7c9fb6c46b7cc9fa3c288ca702c74773968173bda421bf"}, + {file = "cryptography-41.0.5-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:227ec057cd32a41c6651701abc0328135e472ed450f47c2766f23267b792a88e"}, + {file = "cryptography-41.0.5-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:22892cc830d8b2c89ea60148227631bb96a7da0c1b722f2aac8824b1b7c0b6b8"}, + {file = "cryptography-41.0.5-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:5a70187954ba7292c7876734183e810b728b4f3965fbe571421cb2434d279179"}, + {file = "cryptography-41.0.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:88417bff20162f635f24f849ab182b092697922088b477a7abd6664ddd82291d"}, + {file = "cryptography-41.0.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c707f7afd813478e2019ae32a7c49cd932dd60ab2d2a93e796f68236b7e1fbf1"}, + {file = "cryptography-41.0.5-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:580afc7b7216deeb87a098ef0674d6ee34ab55993140838b14c9b83312b37b86"}, + {file = "cryptography-41.0.5-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1e91467c65fe64a82c689dc6cf58151158993b13eb7a7f3f4b7f395636723"}, + {file = "cryptography-41.0.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d2a6a598847c46e3e321a7aef8af1436f11c27f1254933746304ff014664d84"}, + {file = "cryptography-41.0.5.tar.gz", hash = "sha256:392cb88b597247177172e02da6b7a63deeff1937fa6fec3bbf902ebd75d97ec7"}, ] [package.dependencies] @@ -966,69 +966,69 @@ tests = ["pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "cython" -version = "3.0.4" +version = "3.0.5" description = "The Cython compiler for writing C extensions in the Python language." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "Cython-3.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:096cb461bf8d913a4327d93ea38d18bc3dbc577a71d805be04754e4b2cc2c45d"}, - {file = "Cython-3.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf671d712816b48fa2731799017ed68e5e440922d0c7e13dc825c226639ff766"}, - {file = "Cython-3.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:beb367fd88fc6ba8c204786f680229106d99da72a60f5906c85fc8d73640b01a"}, - {file = "Cython-3.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6619264ed43d8d8819d4f1cdb8a62ab66f87e92f06f3ff3e2533fd95a9945e59"}, - {file = "Cython-3.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c0fb9e7cf9db38918f19a803fab9bc7b2ed3f33a9e8319c616c464a0a8501b8d"}, - {file = "Cython-3.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c214f6e88ecdc8ff5d13f0914890445fdaad21bddc34a90cd14aeb3ad5e55e2e"}, - {file = "Cython-3.0.4-cp310-cp310-win32.whl", hash = "sha256:c9b1322f0d8ce5445fcc3a625b966f10c4182190026713e217d6f38d29930cb1"}, - {file = "Cython-3.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:146bfaab567157f4aa34114a37e3f98a3d9c4527ee99d4fd730cab56482bd3cf"}, - {file = "Cython-3.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c8e0f98d950987b0f9d5e10c41236bef5cb4fba701c6e680af0b9734faa3a85e"}, - {file = "Cython-3.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fe227d6d8e2ea030e82abc8a3e361e31447b66849f8c069caa783999e54a8f2"}, - {file = "Cython-3.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6da74000a672eac0d7cf02adc140b2f9c7d54eae6c196e615a1b5deb694d9203"}, - {file = "Cython-3.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48cda82eb82ad2014d2ad194442ed3c46156366be98e4e02f3e29742cdbf94a0"}, - {file = "Cython-3.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4355a2cb03b257773c0d2bb6af9818c72e836a9b09986e28f52e323d87b1fc67"}, - {file = "Cython-3.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:10b426adc3027d66303f5c7aa8b254d10ed80827ff5cce9e892d550b708dc044"}, - {file = "Cython-3.0.4-cp311-cp311-win32.whl", hash = "sha256:28de18f0d07eb34e2dd7b022ac30beab0fdd277846d07b7a08e69e6294f0762b"}, - {file = "Cython-3.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:9d31d76ed777a8a85be3f8f7f1cfef09b3bc33f6ec4abee1067dcef107f49778"}, - {file = "Cython-3.0.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d5a55749509c7f9f8a33bf9cc02cf76fd6564fcb38f486e43d2858145d735953"}, - {file = "Cython-3.0.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58cdfdd942cf5ffcee974aabfe9b9e26c0c1538fd31c1b03596d40405f7f4d40"}, - {file = "Cython-3.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b906997e7b98d7d29b84d10a5318993eba1aaff82ff7e1a0ac00254307913d7"}, - {file = "Cython-3.0.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f24114e1777604a28ae1c7a56a2c9964655f1031edecc448ad51e5abb19a279b"}, - {file = "Cython-3.0.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:07d0e69959f267b79ffd18ece8599711ad2f3d3ed1eddd0d4812d2a97de2b912"}, - {file = "Cython-3.0.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f7fcd93d15deceb2747b10266a39deccd94f257d610f3bbd52a7e16bc5908eda"}, - {file = "Cython-3.0.4-cp312-cp312-win32.whl", hash = "sha256:0aa2a6bb3ff67794d8d1dafaed22913adcbb327e96eca3ac44e2f3ba4a0ae446"}, - {file = "Cython-3.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:0021350f6d7022a37f598320460b84b2c0daccf6bb65641bbdbc8b990bdf4ad2"}, - {file = "Cython-3.0.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b72c426df1586f967b1c61d2f8236702d75c6bbf34abdc258a59e09155a16414"}, - {file = "Cython-3.0.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a9262408f05eef039981479b38b38252d5b853992e5bc54a2d2dd05a2a0178e"}, - {file = "Cython-3.0.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28af4e7dff1742cb0f0a4823102c89c62a2d94115b68f718145fcfe0763c6e21"}, - {file = "Cython-3.0.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e8c144e2c5814e46868d1f81e2f4265ca1f314a8187d0420cd76e9563294cf8"}, - {file = "Cython-3.0.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:19a64bf2591272348ab08bcd4a5f884259cc3186f008c9038b8ec7d01f847fd5"}, - {file = "Cython-3.0.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:fc96efa617184b8581a02663e261b41c13a605da8ef4ba1ed735bf46184f815e"}, - {file = "Cython-3.0.4-cp36-cp36m-win32.whl", hash = "sha256:15d52f7f9d08b264c042aa508bf457f53654b55f533e0262e146002b1c15d1cd"}, - {file = "Cython-3.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:0650460b5fd6f16da4186e0a769b47db5532601e306f3b5d17941283d5e36d24"}, - {file = "Cython-3.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b3ddfc6f05410095ec11491dde05f50973e501567d21cbfcf5832d95f141878a"}, - {file = "Cython-3.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a0b92adfcac68dcf549daddec83c87a86995caa6f87bfb6f72de4797e1a6ad6"}, - {file = "Cython-3.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ada3659608795bb36930d9a206b8dd6b865d85e2999a02ce8b34f3195d88301"}, - {file = "Cython-3.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:061dec1be8d8b601b160582609a78eb08324a4ccf21bee0d04853a3e9dfcbefd"}, - {file = "Cython-3.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:bc42004f181373cd3b39bbacfb71a5b0606ed6e4c199c940cca2212ba0f79525"}, - {file = "Cython-3.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f124ac9ee41e1bfdfb16f53f1db85de296cd2144a4e8fdee8c3560a8fe9b6d5d"}, - {file = "Cython-3.0.4-cp37-cp37m-win32.whl", hash = "sha256:48b35ab009227ee6188991b5666aae1936b82a944f707c042cef267709de12b5"}, - {file = "Cython-3.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:861979428f749faa9883dc4e11e8c3fc2c29bd0031cf49661604459b53ea7c66"}, - {file = "Cython-3.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c7a7dd7c50d07718a5ac2bdea166085565f7217cf1e030cc07c22a8b80a406a7"}, - {file = "Cython-3.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d40d4135f76fb0ed4caa2d422fdb4231616615698709d3c421ecc733f1ac7ca0"}, - {file = "Cython-3.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:207f53893ca22d8c8f5db533f38382eb7ddc2d0b4ab51699bf052423a6febdad"}, - {file = "Cython-3.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0422a40a58dcfbb54c8b4e125461d741031ff046bc678475cc7a6c801d2a7721"}, - {file = "Cython-3.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ef4b144c5b29b4ea0b40c401458b86df8d75382b2e5d03e9f67f607c05b516a9"}, - {file = "Cython-3.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0612439f810cc281e51fead69de0545c4d9772a1e82149c119d1aafc1f6210ba"}, - {file = "Cython-3.0.4-cp38-cp38-win32.whl", hash = "sha256:b86871862bd65806ba0d0aa2b9c77fcdcc6cbd8d36196688f4896a34bb626334"}, - {file = "Cython-3.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:6603a287188dcbc36358a73a7be43e8a2ecf0c6a06835bdfdd1b113943afdd6f"}, - {file = "Cython-3.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0fc9e974419cc0393072b1e9a669f71c3b34209636d2005ff8620687daa82b8c"}, - {file = "Cython-3.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e84988d384dfba678387ea7e4f68786c3703543018d473605d9299c69a07f197"}, - {file = "Cython-3.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36299ffd5663203c25d3a76980f077e23b6d4f574d142f0f43943f57be445639"}, - {file = "Cython-3.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8529cf09919263a6826adc04c5dde9f1406dd7920929b16be19ee9848110e353"}, - {file = "Cython-3.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8692249732d62e049df3884fa601b70fad3358703e137aceeb581e5860e7d9b7"}, - {file = "Cython-3.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f234bc46043856d118ebd94b13ea29df674503bc94ced3d81ca46a1ad5b5b9ae"}, - {file = "Cython-3.0.4-cp39-cp39-win32.whl", hash = "sha256:c2215f436ce3cce49e6e318cb8f7253cfc4d3bea690777c2a5dd52ae93342504"}, - {file = "Cython-3.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:003ccc40e0867770db0018274977d1874e4df64983d5e3e36937f107e0b2fdf6"}, - {file = "Cython-3.0.4-py2.py3-none-any.whl", hash = "sha256:e5e2859f97e9cceb8e70b0934c56157038b8b083245898593008162a70536d7e"}, - {file = "Cython-3.0.4.tar.gz", hash = "sha256:2e379b491ee985d31e5faaf050f79f4a8f59f482835906efe4477b33b4fbe9ff"}, + {file = "Cython-3.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4faf17ea6e8fc3065a862d4b24be84048fd58ed7abe59aa2f9141446a7a72335"}, + {file = "Cython-3.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1cab30c11880f38a27911b569ea38b0bd67fcf32f8a8a8519b613c70562dae2"}, + {file = "Cython-3.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c4d4d92182002b2878adb3329de1ccb7f3f7571d3586f92602e790bfeab45d0"}, + {file = "Cython-3.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b94f58e05e69e1a43da551c8f532e9fad057df1641f0f8ae8f103d4ede5a80fe"}, + {file = "Cython-3.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a90f9c7b6635967eacafebe439d518b7dc720aaaf19cb9553f5aad03c13296f4"}, + {file = "Cython-3.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c95bd21d87b08c88fe5296381a5f39cd979a775bf1a1d7379a6ff87c703e510b"}, + {file = "Cython-3.0.5-cp310-cp310-win32.whl", hash = "sha256:ebc901131057c115a8868e14c1df6e56b9190df774b72664c03ebd858296bb81"}, + {file = "Cython-3.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:0759868b4a4d103578375e031e89abd578c26774d957ee4f591764ef8003b363"}, + {file = "Cython-3.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3679a6693456f5f7ccca9ab2a91408e99ee257e145024fe380da7c78a07e98b6"}, + {file = "Cython-3.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ad4eb2608661d63fb57c674dafb9955f5141d748d4579c7722c1a3c6b86a0c2"}, + {file = "Cython-3.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b37f4b0d983316242b4b9241ecbbe55220aa92af93ff04626441fe0ea90a54f9"}, + {file = "Cython-3.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34059c3ea6e342ba388cd9774a61761bb4200ca18bd475de65c9cc70ef4e0204"}, + {file = "Cython-3.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4db9eea298e982aee7ba12b3432c66eb2e91bb2f5d026bbd57c35698ea0f557f"}, + {file = "Cython-3.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:452679284c15a7d5a88bff675e1dd660349360f0665aea50be2d98b7650925f8"}, + {file = "Cython-3.0.5-cp311-cp311-win32.whl", hash = "sha256:2d6bb318ddce8b978c81cf78caf8b3836db84f6235d721952685e87871f506e4"}, + {file = "Cython-3.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:fcfd2255458a5779dbab813550695331d541b24f0ef831ace83f04f9516ddf26"}, + {file = "Cython-3.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0d9fcfc09d67218fce114fe9fd97bba4f9d56add0f775c588d8c626ed47f1aef"}, + {file = "Cython-3.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ac1cf1f2ed01656b33618352f7e42bf75d027425b83cc96cfe13ce4b6cba5de"}, + {file = "Cython-3.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9d17a6ceb301c5dbd3820e62c1b10a4ad3a6eea3e07e7afaf736b5f490c2e32"}, + {file = "Cython-3.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd9cab3b862bec2b110886aedb11765e9deda363c4c7ab5ea205f3d8f143c411"}, + {file = "Cython-3.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:45277bb54c35b11bcdd6cf0f56eb950eb280b67146db0cb57853fb6334c6d11d"}, + {file = "Cython-3.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:77f4d001fb7a03a68b53be20571acd17452d1dda7907d9c325dff0cc704b1ef9"}, + {file = "Cython-3.0.5-cp312-cp312-win32.whl", hash = "sha256:57b44f789794d74c1feddae054dd045b9f601bdffd7288e069b4ca7ed607ec61"}, + {file = "Cython-3.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:05c4efd36879ff8020af00407e4c14246b894558ea41dc6486f60dd71601fc67"}, + {file = "Cython-3.0.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:048fe89c2c753c24e1a7a05496907173dab17e238c8dc3c7cad90b3679b0d846"}, + {file = "Cython-3.0.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c016b3e859b41cf4ce1b8107f364ad5a83c086f75ea4d8d3990b24691f626a1"}, + {file = "Cython-3.0.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f31d02b831d0fa9bf099b1b714b5a8252eabd8db34b7d33c48e7e808a2dabf9"}, + {file = "Cython-3.0.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:485f8a3087392e2287e2869adc0385b439f69b9cfbd262fdf39b00417690c988"}, + {file = "Cython-3.0.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:063220a6dc0909b576ef068c7e2acf5c608d64423a6d231aacb72d06352cd95b"}, + {file = "Cython-3.0.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:abb2362783521bd9a22fe69b2141abab4db97237665a36a034b161ddee5b3e72"}, + {file = "Cython-3.0.5-cp36-cp36m-win32.whl", hash = "sha256:a993002fe28c840dc29805fde7341c775b7878b311b85f21560fdebf220c247b"}, + {file = "Cython-3.0.5-cp36-cp36m-win_amd64.whl", hash = "sha256:13491f1bfcf020fd02751c4a55294aa8957e21b7ecd2542b0521a7aa50c58bb2"}, + {file = "Cython-3.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:45aaceb082ad89365f2f783a40db42359591ad55914fb298841196edf88afdc5"}, + {file = "Cython-3.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3e011fa2ae9e953fe1ab8394329a21bdb54357c7fe509bcfb02b88bc15bffbb"}, + {file = "Cython-3.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f18c13d5ed6fde5efd3b1c039f6a34296d1a0409bb00fbf45bec6f9bcf63ddf5"}, + {file = "Cython-3.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:039877e57dc10abf0d30d2de2c7476f0881d8ecef1f29bdeed1a6a06a8d89141"}, + {file = "Cython-3.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4fbc8f62b8d50f9a2eef99927a9dcb8d0a42e5a801ab14c2e4aeab622c88f54b"}, + {file = "Cython-3.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3cffbba1888f795de2103e6fb1482c8ea8d457e638fa813e090fe747f9e549bb"}, + {file = "Cython-3.0.5-cp37-cp37m-win32.whl", hash = "sha256:c18e125537a96e76c8c34201e5a9aad8625e3d872dd26a63155573462e54e185"}, + {file = "Cython-3.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:93502f45948ae8d7f874ba4c113b50cb6fb4ee664caa82e1ddc398500ee0ffb3"}, + {file = "Cython-3.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0a9206b0720f0cad3e70c018722f6d10e81b32e65477e14ffedd3fbfadfaddca"}, + {file = "Cython-3.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:530a474a79fa6c2127bb7e3ba00857b1f26a563615863f17b7434331aa3fe404"}, + {file = "Cython-3.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:115e76fbe9288119526b66963f614042222d1587f1ba5ddb90088215a3d2a25a"}, + {file = "Cython-3.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:035cb6930a8534f865a3f4616543f78bd27e4de9c3e117b2826e395085ffc4c0"}, + {file = "Cython-3.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:077d9a61e6042174dabf68b8e92c0a80f5aff529439ed314aa6e6a233af80b95"}, + {file = "Cython-3.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ba3f7b433c1721a43674c0889d5fad746bf608416c8f849343859e6d4d3a7113"}, + {file = "Cython-3.0.5-cp38-cp38-win32.whl", hash = "sha256:a95ed0e6f481462a3ff2be4c2e4ffffc5d00fc3884d4ccd1fe5b702d4938ec09"}, + {file = "Cython-3.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:f687539ead9fbc17f499e33ee20c1dc41598f70ad95edb4990c576447cec9d23"}, + {file = "Cython-3.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f6fcfef825edb44cf3c6ba2c091ad76a83da62ac9c79553e80e0c2a1f75eda2e"}, + {file = "Cython-3.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0d9431101f600d5a557d55989658cbfd02b7c0dcd1e4675dac8ad7e0da8ea5b"}, + {file = "Cython-3.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db21997270e943aee9cb7694112d24a4702fbe1977fbe53b3cb4db3d02be73d9"}, + {file = "Cython-3.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:808f56d4cd0511723b787c341f3cc995fd72893e608102268298c188f4a4f2e7"}, + {file = "Cython-3.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:dee39967168d6326ea2df56ad215a4d5049aa52f44cd5aad45bfb63d5b4fb9e5"}, + {file = "Cython-3.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b77f2b45535bcf3741592fa03183558bd42198b872c1584b896fa0ba5f2ac68d"}, + {file = "Cython-3.0.5-cp39-cp39-win32.whl", hash = "sha256:5742ef31e1e2c9a4824ef6b05af0f4949047a6f73af1d4b238ce12935174aede"}, + {file = "Cython-3.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:ada4852db0e33dbdd1425322db081d22b9725cb9f5eba42885467b4e2c4f2ac0"}, + {file = "Cython-3.0.5-py2.py3-none-any.whl", hash = "sha256:75206369504fc442c10a86ecf57b91592dca744e4592af22a47e9a774d53dd10"}, + {file = "Cython-3.0.5.tar.gz", hash = "sha256:39318348db488a2f24e7c84e08bdc82f2624853c0fea8b475ea0b70b27176492"}, ] [[package]] @@ -1116,19 +1116,19 @@ files = [ [[package]] name = "filelock" -version = "3.12.4" +version = "3.13.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.12.4-py3-none-any.whl", hash = "sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4"}, - {file = "filelock-3.12.4.tar.gz", hash = "sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd"}, + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] -typing = ["typing-extensions (>=4.7.1)"] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] [[package]] name = "fiona" @@ -1632,13 +1632,13 @@ zoneinfo = ["backports.zoneinfo (>=0.2.1)", "tzdata (>=2022.1)"] [[package]] name = "identify" -version = "2.5.30" +version = "2.5.31" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.30-py2.py3-none-any.whl", hash = "sha256:afe67f26ae29bab007ec21b03d4114f41316ab9dd15aa8736a167481e108da54"}, - {file = "identify-2.5.30.tar.gz", hash = "sha256:f302a4256a15c849b91cfcdcec052a8ce914634b2f77ae87dad29cd749f2d88d"}, + {file = "identify-2.5.31-py2.py3-none-any.whl", hash = "sha256:90199cb9e7bd3c5407a9b7e81b4abec4bb9d249991c79439ec8af740afc6293d"}, + {file = "identify-2.5.31.tar.gz", hash = "sha256:7736b3c7a28233637e3c36550646fc6389bedd74ae84cb788200cc8e2dd60b75"}, ] [package.extras] @@ -1908,15 +1908,15 @@ files = [ [[package]] name = "libusb1" -version = "3.0.0" +version = "3.1.0" description = "Pure-python wrapper for libusb-1.0" optional = false python-versions = "*" files = [ - {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"}, + {file = "libusb1-3.1.0-py3-none-any.whl", hash = "sha256:9d9f16e2c199cab91f48ead585d3f5ec7e8e4be428a25ddfed22abf786fa9b3a"}, + {file = "libusb1-3.1.0-py3-none-win32.whl", hash = "sha256:bc7874302565721f443a27d8182fcc7152e5b560523f12f1377b130f473e4a0c"}, + {file = "libusb1-3.1.0-py3-none-win_amd64.whl", hash = "sha256:77a06ecfb3d002d7c2ce369e28d0138b292fe8db8a3d102b73fda231a716dd35"}, + {file = "libusb1-3.1.0.tar.gz", hash = "sha256:4ee9b0a55f8bd0b3ea7017ae919a6c1f439af742c4a4b04543c5fd7af89b828c"}, ] [[package]] @@ -2703,51 +2703,44 @@ files = [ [[package]] name = "onnx" -version = "1.14.1" +version = "1.15.0" description = "Open Neural Network Exchange" optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "onnx-1.14.1-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:05d8609b4148f8ee4bd5d8186875ccb288300106242fc5201b8b575681bbd5c4"}, - {file = "onnx-1.14.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f131c2fd36f7848437be9de3b1fa5449a94245e16c6f275f66ac7cf8f183ec26"}, - {file = "onnx-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea8d7abe048d0e9e31541dc62e9e40b8411b11377d2a22ed842e678802b4e1aa"}, - {file = "onnx-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:921ad325b17484698d9d65978e123b1f351328ea50de6f84f25d09d5c7dde361"}, - {file = "onnx-1.14.1-cp310-cp310-win32.whl", hash = "sha256:6c8156be97762814c7c835d597320ef1f6630f034344fbc672cd6edddbbf78ee"}, - {file = "onnx-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:776ab461515c20cc4e24dbd75af32b6b1e64de931dc5873b049f13bfec1c96e9"}, - {file = "onnx-1.14.1-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:93e614edaf87ea1adba24663780ac62e30f421c117d695379daa9ff816de821b"}, - {file = "onnx-1.14.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:65672ae827ea5f0e59dc0d1cef1c0ed5083d5e8348946f98f1715ebb123573e9"}, - {file = "onnx-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6efa7375d91b1da10badd1d2701a94b0e9b111a5e1a227be1bf877450cea84ac"}, - {file = "onnx-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9cd91b85cfbb0d6478f4a1a0aee4d95cf8839adc48c69130a0cf8452f21db4"}, - {file = "onnx-1.14.1-cp311-cp311-win32.whl", hash = "sha256:1072baf93e04bbbed45f8f997cbbe96e179080b4cd95bc676882fe64aa709dd6"}, - {file = "onnx-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:16a6667aff34431ab828b393ed8153c0a0cf15152d76f8d93aa48fb206217827"}, - {file = "onnx-1.14.1-cp37-cp37m-macosx_10_12_universal2.whl", hash = "sha256:3fde9e1854e525aae93b403c1174bf68dc86ac92b6f8fb4af0fe3ec0d1440631"}, - {file = "onnx-1.14.1-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:58e6eb27c99dbefc84b4234388f5f668b49a1aaeced1580cb96f5fe05800a77c"}, - {file = "onnx-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84653e8e19f5d051f9e7ed9cf7285527fd34e093e3b50554121849664e97c254"}, - {file = "onnx-1.14.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b4a0e029b3604dc5294a7333f622d8c04d6a6a1bc4f51054195074f61b8f41a"}, - {file = "onnx-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:f5046bfbe7f9bab59fc53984aaa5b47a35c8f8e98787053e1650049a1aaf12de"}, - {file = "onnx-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:b37e7bd8baf75efa78ecce713273e2aa29c8c06f69cee6107b413cd03bf59b20"}, - {file = "onnx-1.14.1-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:758dc585885e997f1086019f098e7ce0a4b3ab7d5a89bb2093572bb68ea906c1"}, - {file = "onnx-1.14.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:486ced7588437ff08a03914ac110d64caa686ff7fa766123d15c8d8eeec29210"}, - {file = "onnx-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:498ecc3e545b80685501c26b62eeeda0b8ae2f2ba8ff3f650ce1f526924aa699"}, - {file = "onnx-1.14.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e991e867b799df0d7ed4cdad94c6a3ed9bebaceef3e574ac9eed314e1bfca0ef"}, - {file = "onnx-1.14.1-cp38-cp38-win32.whl", hash = "sha256:a8c3b1398b156f8bae9882ed8c602e1aa5171180fffcbeb1f9a337fe307c1df4"}, - {file = "onnx-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:cf20e7a346d22468a128a40c5cc1f4d20c3939e21e74fc8e3be8ba66c6f82444"}, - {file = "onnx-1.14.1-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:17f78637d2f6c3c9afad0611fe4c583b6ba4839ac724af0846e5db24dc8dadc0"}, - {file = "onnx-1.14.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:60ad73263a06056f9aa288b082887c6330be08475471c3a009f62439b2a67dca"}, - {file = "onnx-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:030aa47e28337fd81f4d884032660e40912a4763ce4e5a4b4144380271390e82"}, - {file = "onnx-1.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b113fa0183034743e6477fec928e478a6d94eee8d9a4376c144d20d736cdc45"}, - {file = "onnx-1.14.1-cp39-cp39-win32.whl", hash = "sha256:b9c28a99d4a620cb1d31120d35e0fab54073b9725ed50c3cd3ec7beb876e8dba"}, - {file = "onnx-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:bdb15fc4b7f2a8a19abb52ac9672db876f9505e7219e206bcb7530e7c1274e55"}, - {file = "onnx-1.14.1.tar.gz", hash = "sha256:70903afe163643bd71195c78cedcc3f4fa05a2af651fd950ef3acbb15175b2d1"}, + {file = "onnx-1.15.0-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:51cacb6aafba308aaf462252ced562111f6991cdc7bc57a6c554c3519453a8ff"}, + {file = "onnx-1.15.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:0aee26b6f7f7da7e840de75ad9195a77a147d0662c94eaa6483be13ba468ffc1"}, + {file = "onnx-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baf6ef6c93b3b843edb97a8d5b3d229a1301984f3f8dee859c29634d2083e6f9"}, + {file = "onnx-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ed899fe6000edc05bb2828863d3841cfddd5a7cf04c1a771f112e94de75d9f"}, + {file = "onnx-1.15.0-cp310-cp310-win32.whl", hash = "sha256:f1ad3d77fc2f4b4296f0ac2c8cadd8c1dcf765fc586b737462d3a0fe8f7c696a"}, + {file = "onnx-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:ca4ebc4f47109bfb12c8c9e83dd99ec5c9f07d2e5f05976356c6ccdce3552010"}, + {file = "onnx-1.15.0-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:233ffdb5ca8cc2d960b10965a763910c0830b64b450376da59207f454701f343"}, + {file = "onnx-1.15.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:51fa79c9ea9af033638ec51f9177b8e76c55fad65bb83ea96ee88fafade18ee7"}, + {file = "onnx-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f277d4861729f5253a51fa41ce91bfec1c4574ee41b5637056b43500917295ce"}, + {file = "onnx-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8a7c94d2ebead8f739fdb70d1ce5a71726f4e17b3e5b8ad64455ea1b2801a85"}, + {file = "onnx-1.15.0-cp311-cp311-win32.whl", hash = "sha256:17dcfb86a8c6bdc3971443c29b023dd9c90ff1d15d8baecee0747a6b7f74e650"}, + {file = "onnx-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:60a3e28747e305cd2e766e6a53a0a6d952cf9e72005ec6023ce5e07666676a4e"}, + {file = "onnx-1.15.0-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:6b5c798d9e0907eaf319e3d3e7c89a2ed9a854bcb83da5fefb6d4c12d5e90721"}, + {file = "onnx-1.15.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:a4f774ff50092fe19bd8f46b2c9b27b1d30fbd700c22abde48a478142d464322"}, + {file = "onnx-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2b0e7f3938f2d994c34616bfb8b4b1cebbc4a0398483344fe5e9f2fe95175e6"}, + {file = "onnx-1.15.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49cebebd0020a4b12c1dd0909d426631212ef28606d7e4d49463d36abe7639ad"}, + {file = "onnx-1.15.0-cp38-cp38-win32.whl", hash = "sha256:1fdf8a3ff75abc2b32c83bf27fb7c18d6b976c9c537263fadd82b9560fe186fa"}, + {file = "onnx-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:763e55c26e8de3a2dce008d55ae81b27fa8fb4acbb01a29b9f3c01f200c4d676"}, + {file = "onnx-1.15.0-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:b2d5e802837629fc9c86f19448d19dd04d206578328bce202aeb3d4bedab43c4"}, + {file = "onnx-1.15.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:9a9cfbb5e5d5d88f89d0dfc9df5fb858899db874e1d5ed21e76c481f3cafc90d"}, + {file = "onnx-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f472bbe5cb670a0a4a4db08f41fde69b187a009d0cb628f964840d3f83524e9"}, + {file = "onnx-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bf2de9bef64792e5b8080c678023ac7d2b9e05d79a3e17e92cf6a4a624831d2"}, + {file = "onnx-1.15.0-cp39-cp39-win32.whl", hash = "sha256:ef4d9eb44b111e69e4534f3233fc2c13d1e26920d24ae4359d513bd54694bc6d"}, + {file = "onnx-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:95d7a3e2d79d371e272e39ae3f7547e0b116d0c7f774a4004e97febe6c93507f"}, + {file = "onnx-1.15.0.tar.gz", hash = "sha256:b18461a7d38f286618ca2a6e78062a2a9c634ce498e631e708a8041b00094825"}, ] [package.dependencies] numpy = "*" protobuf = ">=3.20.2" -typing-extensions = ">=3.6.2.1" [package.extras] -lint = ["lintrunner (>=0.10.0)", "lintrunner-adapters (>=0.3)"] +reference = ["Pillow", "google-re2"] [[package]] name = "onnxruntime" @@ -2983,40 +2976,40 @@ test = ["pylint (==2.4.*)", "pytest", "pytest-pylint"] [[package]] name = "pandas" -version = "2.1.1" +version = "2.1.2" description = "Powerful data structures for data analysis, time series, and statistics" optional = false python-versions = ">=3.9" files = [ - {file = "pandas-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:58d997dbee0d4b64f3cb881a24f918b5f25dd64ddf31f467bb9b67ae4c63a1e4"}, - {file = "pandas-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02304e11582c5d090e5a52aec726f31fe3f42895d6bfc1f28738f9b64b6f0614"}, - {file = "pandas-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffa8f0966de2c22de408d0e322db2faed6f6e74265aa0856f3824813cf124363"}, - {file = "pandas-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1f84c144dee086fe4f04a472b5cd51e680f061adf75c1ae4fc3a9275560f8f4"}, - {file = "pandas-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:75ce97667d06d69396d72be074f0556698c7f662029322027c226fd7a26965cb"}, - {file = "pandas-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:4c3f32fd7c4dccd035f71734df39231ac1a6ff95e8bdab8d891167197b7018d2"}, - {file = "pandas-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e2959720b70e106bb1d8b6eadd8ecd7c8e99ccdbe03ee03260877184bb2877d"}, - {file = "pandas-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:25e8474a8eb258e391e30c288eecec565bfed3e026f312b0cbd709a63906b6f8"}, - {file = "pandas-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8bd1685556f3374520466998929bade3076aeae77c3e67ada5ed2b90b4de7f0"}, - {file = "pandas-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc3657869c7902810f32bd072f0740487f9e030c1a3ab03e0af093db35a9d14e"}, - {file = "pandas-2.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:05674536bd477af36aa2effd4ec8f71b92234ce0cc174de34fd21e2ee99adbc2"}, - {file = "pandas-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:b407381258a667df49d58a1b637be33e514b07f9285feb27769cedb3ab3d0b3a"}, - {file = "pandas-2.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c747793c4e9dcece7bb20156179529898abf505fe32cb40c4052107a3c620b49"}, - {file = "pandas-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3bcad1e6fb34b727b016775bea407311f7721db87e5b409e6542f4546a4951ea"}, - {file = "pandas-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5ec7740f9ccb90aec64edd71434711f58ee0ea7f5ed4ac48be11cfa9abf7317"}, - {file = "pandas-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29deb61de5a8a93bdd033df328441a79fcf8dd3c12d5ed0b41a395eef9cd76f0"}, - {file = "pandas-2.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4f99bebf19b7e03cf80a4e770a3e65eee9dd4e2679039f542d7c1ace7b7b1daa"}, - {file = "pandas-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:84e7e910096416adec68075dc87b986ff202920fb8704e6d9c8c9897fe7332d6"}, - {file = "pandas-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:366da7b0e540d1b908886d4feb3d951f2f1e572e655c1160f5fde28ad4abb750"}, - {file = "pandas-2.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9e50e72b667415a816ac27dfcfe686dc5a0b02202e06196b943d54c4f9c7693e"}, - {file = "pandas-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc1ab6a25da197f03ebe6d8fa17273126120874386b4ac11c1d687df288542dd"}, - {file = "pandas-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0dbfea0dd3901ad4ce2306575c54348d98499c95be01b8d885a2737fe4d7a98"}, - {file = "pandas-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0489b0e6aa3d907e909aef92975edae89b1ee1654db5eafb9be633b0124abe97"}, - {file = "pandas-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:4cdb0fab0400c2cb46dafcf1a0fe084c8bb2480a1fa8d81e19d15e12e6d4ded2"}, - {file = "pandas-2.1.1.tar.gz", hash = "sha256:fecb198dc389429be557cde50a2d46da8434a17fe37d7d41ff102e3987fd947b"}, + {file = "pandas-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:24057459f19db9ebb02984c6fdd164a970b31a95f38e4a49cf7615b36a1b532c"}, + {file = "pandas-2.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a6cf8fcc8a63d333970b950a7331a30544cf59b1a97baf0a7409e09eafc1ac38"}, + {file = "pandas-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ae6ffbd9d614c20d028c7117ee911fc4e266b4dca2065d5c5909e401f8ff683"}, + {file = "pandas-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff794eeb7883c5aefb1ed572e7ff533ae779f6c6277849eab9e77986e352688"}, + {file = "pandas-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:02954e285e8e2f4006b6f22be6f0df1f1c3c97adbb7ed211c6b483426f20d5c8"}, + {file = "pandas-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:5b40c9f494e1f27588c369b9e4a6ca19cd924b3a0e1ef9ef1a8e30a07a438f43"}, + {file = "pandas-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:08d287b68fd28906a94564f15118a7ca8c242e50ae7f8bd91130c362b2108a81"}, + {file = "pandas-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bbd98dcdcd32f408947afdb3f7434fade6edd408c3077bbce7bd840d654d92c6"}, + {file = "pandas-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e90c95abb3285d06f6e4feedafc134306a8eced93cb78e08cf50e224d5ce22e2"}, + {file = "pandas-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52867d69a54e71666cd184b04e839cff7dfc8ed0cd6b936995117fdae8790b69"}, + {file = "pandas-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8d0382645ede2fde352da2a885aac28ec37d38587864c0689b4b2361d17b1d4c"}, + {file = "pandas-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:65177d1c519b55e5b7f094c660ed357bb7d86e799686bb71653b8a4803d8ff0d"}, + {file = "pandas-2.1.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5aa6b86802e8cf7716bf4b4b5a3c99b12d34e9c6a9d06dad254447a620437931"}, + {file = "pandas-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d594e2ce51b8e0b4074e6644758865dc2bb13fd654450c1eae51201260a539f1"}, + {file = "pandas-2.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3223f997b6d2ebf9c010260cf3d889848a93f5d22bb4d14cd32638b3d8bba7ad"}, + {file = "pandas-2.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4944dc004ca6cc701dfa19afb8bdb26ad36b9bed5bcec617d2a11e9cae6902"}, + {file = "pandas-2.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3f76280ce8ec216dde336e55b2b82e883401cf466da0fe3be317c03fb8ee7c7d"}, + {file = "pandas-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:7ad20d24acf3a0042512b7e8d8fdc2e827126ed519d6bd1ed8e6c14ec8a2c813"}, + {file = "pandas-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:021f09c15e1381e202d95d4a21ece8e7f2bf1388b6d7e9cae09dfe27bd2043d1"}, + {file = "pandas-2.1.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7f12b2de0060b0b858cfec0016e7d980ae5bae455a1746bfcc70929100ee633"}, + {file = "pandas-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c166b9bb27c1715bed94495d9598a7f02950b4749dba9349c1dd2cbf10729d"}, + {file = "pandas-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25c9976c17311388fcd953cb3d0697999b2205333f4e11e669d90ff8d830d429"}, + {file = "pandas-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:851b5afbb0d62f6129ae891b533aa508cc357d5892c240c91933d945fff15731"}, + {file = "pandas-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:e78507adcc730533619de07bfdd1c62b2918a68cd4419ea386e28abf7f6a1e5c"}, + {file = "pandas-2.1.2.tar.gz", hash = "sha256:52897edc2774d2779fbeb6880d2cfb305daa0b1a29c16b91f531a18918a6e0f3"}, ] [package.dependencies] -numpy = {version = ">=1.23.2", markers = "python_version == \"3.11\""} +numpy = {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""} python-dateutil = ">=2.8.2" pytz = ">=2020.1" tzdata = ">=2022.1" @@ -3472,6 +3465,8 @@ files = [ {file = "pygame-2.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e24d05184e4195fe5ebcdce8b18ecb086f00182b9ae460a86682d312ce8d31f"}, {file = "pygame-2.5.2-cp311-cp311-win32.whl", hash = "sha256:f02c1c7505af18d426d355ac9872bd5c916b27f7b0fe224749930662bea47a50"}, {file = "pygame-2.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:6d58c8cf937815d3b7cdc0fa9590c5129cb2c9658b72d00e8a4568dea2ff1d42"}, + {file = "pygame-2.5.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1a2a43802bb5e89ce2b3b775744e78db4f9a201bf8d059b946c61722840ceea8"}, + {file = "pygame-2.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1c289f2613c44fe70a1e40769de4a49c5ab5a29b9376f1692bb1a15c9c1c9bfa"}, {file = "pygame-2.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:074aa6c6e110c925f7f27f00c7733c6303407edc61d738882985091d1eb2ef17"}, {file = "pygame-2.5.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe0228501ec616779a0b9c4299e837877783e18df294dd690b9ab0eed3d8aaab"}, {file = "pygame-2.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31648d38ecdc2335ffc0e38fb18a84b3339730521505dac68514f83a1092e3f4"}, @@ -3685,20 +3680,20 @@ test = ["Mako", "pytest (>=7.0.0)"] [[package]] name = "pyopenssl" -version = "23.2.0" +version = "23.3.0" description = "Python wrapper module around the OpenSSL library" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "pyOpenSSL-23.2.0-py3-none-any.whl", hash = "sha256:24f0dc5227396b3e831f4c7f602b950a5e9833d292c8e4a2e06b709292806ae2"}, - {file = "pyOpenSSL-23.2.0.tar.gz", hash = "sha256:276f931f55a452e7dea69c7173e984eb2a4407ce413c918aa34b55f82f9b8bac"}, + {file = "pyOpenSSL-23.3.0-py3-none-any.whl", hash = "sha256:6756834481d9ed5470f4a9393455154bc92fe7a64b7bc6ee2c804e78c52099b2"}, + {file = "pyOpenSSL-23.3.0.tar.gz", hash = "sha256:6b2cba5cc46e822750ec3e5a81ee12819850b11303630d575e98108a079c2b12"}, ] [package.dependencies] -cryptography = ">=38.0.0,<40.0.0 || >40.0.0,<40.0.1 || >40.0.1,<42" +cryptography = ">=41.0.5,<42" [package.extras] -docs = ["sphinx (!=5.2.0,!=5.2.0.post0)", "sphinx-rtd-theme"] +docs = ["sphinx (!=5.2.0,!=5.2.0.post0,!=7.2.5)", "sphinx-rtd-theme"] test = ["flaky", "pretend", "pytest (>=3.0.1)"] [[package]] @@ -3827,13 +3822,13 @@ cp2110 = ["hidapi"] [[package]] name = "pytest" -version = "7.4.2" +version = "7.4.3" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, - {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, + {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, + {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, ] [package.dependencies] @@ -4206,28 +4201,28 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "ruff" -version = "0.1.1" +version = "0.1.3" description = "An extremely fast Python linter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.1.1-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:b7cdc893aef23ccc14c54bd79a8109a82a2c527e11d030b62201d86f6c2b81c5"}, - {file = "ruff-0.1.1-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:620d4b34302538dbd8bbbe8fdb8e8f98d72d29bd47e972e2b59ce6c1e8862257"}, - {file = "ruff-0.1.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a909d3930afdbc2e9fd893b0034479e90e7981791879aab50ce3d9f55205bd6"}, - {file = "ruff-0.1.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3305d1cb4eb8ff6d3e63a48d1659d20aab43b49fe987b3ca4900528342367145"}, - {file = "ruff-0.1.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c34ae501d0ec71acf19ee5d4d889e379863dcc4b796bf8ce2934a9357dc31db7"}, - {file = "ruff-0.1.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6aa7e63c3852cf8fe62698aef31e563e97143a4b801b57f920012d0e07049a8d"}, - {file = "ruff-0.1.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2d68367d1379a6b47e61bc9de144a47bcdb1aad7903bbf256e4c3d31f11a87ae"}, - {file = "ruff-0.1.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bc11955f6ce3398d2afe81ad7e49d0ebf0a581d8bcb27b8c300281737735e3a3"}, - {file = "ruff-0.1.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbbd8eead88ea83a250499074e2a8e9d80975f0b324b1e2e679e4594da318c25"}, - {file = "ruff-0.1.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f4780e2bb52f3863a565ec3f699319d3493b83ff95ebbb4993e59c62aaf6e75e"}, - {file = "ruff-0.1.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8f5b24daddf35b6c207619301170cae5d2699955829cda77b6ce1e5fc69340df"}, - {file = "ruff-0.1.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d3f9ac658ba29e07b95c80fa742b059a55aefffa8b1e078bc3c08768bdd4b11a"}, - {file = "ruff-0.1.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3521bf910104bf781e6753282282acc145cbe3eff79a1ce6b920404cd756075a"}, - {file = "ruff-0.1.1-py3-none-win32.whl", hash = "sha256:ba3208543ab91d3e4032db2652dcb6c22a25787b85b8dc3aeff084afdc612e5c"}, - {file = "ruff-0.1.1-py3-none-win_amd64.whl", hash = "sha256:3ff3006c97d9dc396b87fb46bb65818e614ad0181f059322df82bbfe6944e264"}, - {file = "ruff-0.1.1-py3-none-win_arm64.whl", hash = "sha256:e140bd717c49164c8feb4f65c644046fe929c46f42493672853e3213d7bdbce2"}, - {file = "ruff-0.1.1.tar.gz", hash = "sha256:c90461ae4abec261609e5ea436de4a4b5f2822921cf04c16d2cc9327182dbbcc"}, + {file = "ruff-0.1.3-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:b46d43d51f7061652eeadb426a9e3caa1e0002470229ab2fc19de8a7b0766901"}, + {file = "ruff-0.1.3-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:b8afeb9abd26b4029c72adc9921b8363374f4e7edb78385ffaa80278313a15f9"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca3cf365bf32e9ba7e6db3f48a4d3e2c446cd19ebee04f05338bc3910114528b"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4874c165f96c14a00590dcc727a04dca0cfd110334c24b039458c06cf78a672e"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eec2dd31eed114e48ea42dbffc443e9b7221976554a504767ceaee3dd38edeb8"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:dc3ec4edb3b73f21b4aa51337e16674c752f1d76a4a543af56d7d04e97769613"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e3de9ed2e39160800281848ff4670e1698037ca039bda7b9274f849258d26ce"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c595193881922cc0556a90f3af99b1c5681f0c552e7a2a189956141d8666fe8"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f75e670d529aa2288cd00fc0e9b9287603d95e1536d7a7e0cafe00f75e0dd9d"}, + {file = "ruff-0.1.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:76dd49f6cd945d82d9d4a9a6622c54a994689d8d7b22fa1322983389b4892e20"}, + {file = "ruff-0.1.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:918b454bc4f8874a616f0d725590277c42949431ceb303950e87fef7a7d94cb3"}, + {file = "ruff-0.1.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d8859605e729cd5e53aa38275568dbbdb4fe882d2ea2714c5453b678dca83784"}, + {file = "ruff-0.1.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0b6c55f5ef8d9dd05b230bb6ab80bc4381ecb60ae56db0330f660ea240cb0d4a"}, + {file = "ruff-0.1.3-py3-none-win32.whl", hash = "sha256:3e7afcbdcfbe3399c34e0f6370c30f6e529193c731b885316c5a09c9e4317eef"}, + {file = "ruff-0.1.3-py3-none-win_amd64.whl", hash = "sha256:7a18df6638cec4a5bd75350639b2bb2a2366e01222825562c7346674bdceb7ea"}, + {file = "ruff-0.1.3-py3-none-win_arm64.whl", hash = "sha256:12fd53696c83a194a2db7f9a46337ce06445fb9aa7d25ea6f293cf75b21aca9f"}, + {file = "ruff-0.1.3.tar.gz", hash = "sha256:3ba6145369a151401d5db79f0a47d50e470384d0d89d0d6f7fab0b589ad07c34"}, ] [[package]] From bf5a45ed9826af7dbf9e1db82413e1340bbfa074 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 1 Nov 2023 02:34:54 +0800 Subject: [PATCH 070/133] cabana: fix messages not updated correctly after `seekto()` (#30351) fix messages not updated correctly after seekto --- tools/cabana/messageswidget.cc | 31 ++++++++++++++++--------------- tools/cabana/messageswidget.h | 7 ++++--- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 29596e325323563..7d4938e42745cd6 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -186,20 +186,21 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { }; const auto &item = items_[index.row()]; + const auto &data = can->lastMessage(item.id); if (role == Qt::DisplayRole) { switch (index.column()) { case Column::NAME: return item.name; case Column::SOURCE: return item.id.source != INVALID_SOURCE ? QString::number(item.id.source) : "N/A"; case Column::ADDRESS: return QString::number(item.id.address, 16); case Column::NODE: return item.node; - case Column::FREQ: return item.id.source != INVALID_SOURCE ? getFreq(*item.data) : "N/A"; - case Column::COUNT: return item.id.source != INVALID_SOURCE ? QString::number(item.data->count) : "N/A"; + case Column::FREQ: return item.id.source != INVALID_SOURCE ? getFreq(data) : "N/A"; + case Column::COUNT: return item.id.source != INVALID_SOURCE ? QString::number(data.count) : "N/A"; case Column::DATA: return item.id.source != INVALID_SOURCE ? "" : "N/A"; } } else if (role == ColorsRole) { - return QVariant::fromValue((void*)(&item.data->colors)); + return QVariant::fromValue((void*)(&data.colors)); } else if (role == BytesRole && index.column() == Column::DATA && item.id.source != INVALID_SOURCE) { - return QVariant::fromValue((void*)(&item.data->dat)); + return QVariant::fromValue((void*)(&data.dat)); } else if (role == Qt::ToolTipRole && index.column() == Column::NAME) { auto msg = dbc()->msg(item.id); auto tooltip = item.name; @@ -219,7 +220,7 @@ void MessageListModel::dbcModified() { for (const auto &[_, m] : dbc()->getMessages(-1)) { dbc_messages_.insert(MessageId{.source = INVALID_SOURCE, .address = m.address}); } - filterAndSort(true); + filterAndSort(); } void MessageListModel::sortItems(std::vector &items) { @@ -233,8 +234,8 @@ void MessageListModel::sortItems(std::vector &items) { case Column::SOURCE: do_sort(items, [](auto &item) { return std::tie(item.id.source, item.id); }); break; case Column::ADDRESS: do_sort(items, [](auto &item) { return std::tie(item.id.address, item.id);}); break; case Column::NODE: do_sort(items, [](auto &item) { return std::tie(item.node, item.id);}); break; - case Column::FREQ: do_sort(items, [](auto &item) { return std::tie(item.data->freq, item.id); }); break; - case Column::COUNT: do_sort(items, [](auto &item) { return std::tie(item.data->count, item.id); }); break; + case Column::FREQ: do_sort(items, [](auto &item) { return std::make_pair(can->lastMessage(item.id).freq, item.id); }); break; + case Column::COUNT: do_sort(items, [](auto &item) { return std::make_pair(can->lastMessage(item.id).count, item.id); }); break; } } @@ -258,6 +259,7 @@ bool MessageListModel::match(const MessageListModel::Item &item) { return true; bool match = true; + const auto &data = can->lastMessage(item.id); for (auto it = filters_.cbegin(); it != filters_.cend() && match; ++it) { const QString &txt = it.value(); switch (it.key()) { @@ -282,20 +284,20 @@ bool MessageListModel::match(const MessageListModel::Item &item) { break; case Column::FREQ: // TODO: Hide stale messages? - match = parseRange(txt, item.data->freq); + match = parseRange(txt, data.freq); break; case Column::COUNT: - match = parseRange(txt, item.data->count); + match = parseRange(txt, data.count); break; case Column::DATA: - match = utils::toHex(item.data->dat).contains(txt, Qt::CaseInsensitive); + match = utils::toHex(data.dat).contains(txt, Qt::CaseInsensitive); break; } } return match; } -void MessageListModel::filterAndSort(bool force_reset) { +void MessageListModel::filterAndSort() { // merge CAN and DBC messages std::vector all_messages; all_messages.reserve(can->lastMessages().size() + dbc_messages_.size()); @@ -304,7 +306,7 @@ void MessageListModel::filterAndSort(bool force_reset) { all_messages.push_back(id); dbc_msgs.erase(MessageId{.source = INVALID_SOURCE, .address = id.address}); } - std::copy(dbc_msgs.begin(), dbc_msgs.end(), std::back_inserter(all_messages)); + all_messages.insert(all_messages.end(), dbc_msgs.begin(), dbc_msgs.end()); // filter and sort std::vector items; @@ -312,14 +314,13 @@ void MessageListModel::filterAndSort(bool force_reset) { auto msg = dbc()->msg(id); Item item = {.id = id, .name = msg ? msg->name : UNTITLED, - .node = msg ? msg->transmitter : QString(), - .data = &can->lastMessage(id)}; + .node = msg ? msg->transmitter : QString()}; if (match(item)) items.emplace_back(item); } sortItems(items); - if (force_reset || items_ != items) { + if (items_ != items) { beginResetModel(); items_ = std::move(items); endResetModel(); diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 063154a2e54fc12..d51dae4142277e3 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -38,15 +38,16 @@ Q_OBJECT void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; void setFilterStrings(const QMap &filters); void msgsReceived(const std::set *new_msgs, bool has_new_ids); - void filterAndSort(bool force_reset = false); + void filterAndSort(); void dbcModified(); struct Item { MessageId id; QString name; QString node; - const CanData *data; - bool operator==(const Item &other) const { return id == other.id; } + bool operator==(const Item &other) const { + return id == other.id && name == other.name && node == other.node; + } }; std::vector items_; From ab637f2ae0fcf0661a2c7486b1134d1bacbe5f2e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 31 Oct 2023 20:34:06 -0700 Subject: [PATCH 071/133] Hyundai: add missing Tucson Hybrid 2024 FW (#30356) * add missing hev tucson 2024 fw * bump MY --- 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 c720e93fd94e127..a7eb0a120b0a699 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -110,7 +110,7 @@ A supported vehicle is one that just works when you install a comma device. All |Hyundai|Tucson 2022[6](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Hyundai|Tucson 2023[6](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |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)](##)|
Parts- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Hyundai|Tucson Hybrid 2022-23[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Hyundai|Tucson Hybrid 2022-24[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |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)](##)|
Parts- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |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)](##)|
Parts- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |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)](##)|
Parts- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 209153c4a4554bd..e20bbe279b1a9e9 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -221,7 +221,7 @@ def init_make(self, CP: car.CarParams): HyundaiCarInfo("Hyundai Tucson 2022", car_parts=CarParts.common([CarHarness.hyundai_n])), HyundaiCarInfo("Hyundai Tucson 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_n])), ], - CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_n])), + CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022-24", "All", car_parts=CarParts.common([CarHarness.hyundai_n])), CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2022-23", car_parts=CarParts.common([CarHarness.hyundai_n])), CAR.CUSTIN_1ST_GEN: HyundaiCarInfo("Hyundai Custin 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_k])), @@ -1963,6 +1963,7 @@ def match_fw_to_car_fuzzy(live_fw_versions) -> Set[str]: b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9100 14A', b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9250 14W', b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 2.02 99211-N9000 14E', + b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9260 14Y', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00NX4__ 1.00 1.00 99110-N9100 ', From 7bee13e2d1a602dde52878bde0d9d81c1fa44b1d Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 1 Nov 2023 14:48:49 -0700 Subject: [PATCH 072/133] raise gpu clock (#30358) * raise gpu clock * update modeld power draw --- system/hardware/tici/hardware.py | 2 +- system/hardware/tici/tests/test_power_draw.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index 7f8ef37f1a0731a..d3375831ad714c4 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -505,7 +505,7 @@ def initialize_hardware(self): sudo_write("1", "/sys/class/kgsl/kgsl-3d0/force_rail_on") sudo_write("1000", "/sys/class/kgsl/kgsl-3d0/idle_timer") sudo_write("performance", "/sys/class/kgsl/kgsl-3d0/devfreq/governor") - sudo_write("596", "/sys/class/kgsl/kgsl-3d0/max_clock_mhz") + sudo_write("710", "/sys/class/kgsl/kgsl-3d0/max_clock_mhz") # setup governors sudo_write("performance", "/sys/class/devfreq/soc:qcom,cpubw/governor") diff --git a/system/hardware/tici/tests/test_power_draw.py b/system/hardware/tici/tests/test_power_draw.py index 1ec9b6ec5920713..659ed16e22d3ada 100755 --- a/system/hardware/tici/tests/test_power_draw.py +++ b/system/hardware/tici/tests/test_power_draw.py @@ -28,7 +28,7 @@ class Proc: PROCS = [ Proc('camerad', 2.1, msgs=['roadCameraState', 'wideRoadCameraState', 'driverCameraState']), - Proc('modeld', 1.0, atol=0.2, msgs=['modelV2']), + Proc('modeld', 1.12, atol=0.2, msgs=['modelV2']), Proc('dmonitoringmodeld', 0.4, msgs=['driverStateV2']), Proc('encoderd', 0.23, msgs=[]), Proc('mapsd', 0.05, msgs=['mapRenderState']), From ddbdaf3cf97f0db02f355110615789e09936220c Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Wed, 1 Nov 2023 20:31:54 -0400 Subject: [PATCH 073/133] test_onroad: assert the procs that use the GPU (#30359) * test gpu * keep it localiized * has to be later * reduce diff --------- Co-authored-by: Comma Device --- selfdrive/test/test_onroad.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index e4f6bccf6cd71f0..841c77f142a45f8 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -3,6 +3,8 @@ import math import json import os +import pathlib +import psutil import shutil import subprocess import time @@ -151,6 +153,8 @@ def setUpClass(cls): cls.segments = cls.segments[:-1] finally: + cls.gpu_procs = {psutil.Process(int(f.name)).name() for f in pathlib.Path('/sys/devices/virtual/kgsl/kgsl/proc/').iterdir() if f.is_dir()} + if proc is not None: proc.terminate() if proc.wait(60) is None: @@ -296,6 +300,9 @@ def test_memory_usage(self): # expected to go up while the MSGQ buffers fill up self.assertLessEqual(max(mems) - min(mems), 3.0) + def test_gpu_usage(self): + self.assertEqual(self.gpu_procs, {"weston", "_ui", "mapsd", "camerad", "selfdrive.modeld.modeld"}) + def test_camera_processing_time(self): result = "\n" result += "------------------------------------------------\n" From 0c6101e267839cfef80bd0bcc0866259ef8fc3a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Wed, 1 Nov 2023 18:04:28 -0700 Subject: [PATCH 074/133] bodyteleop: fix browser audioinput (#30360) Fix browser mic in bodyteleop --- tools/bodyteleop/static/js/webrtc.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/bodyteleop/static/js/webrtc.js b/tools/bodyteleop/static/js/webrtc.js index 7668c1c1e48b3a2..e2f6583c17b4ac2 100644 --- a/tools/bodyteleop/static/js/webrtc.js +++ b/tools/bodyteleop/static/js/webrtc.js @@ -89,18 +89,18 @@ export const constraints = { export function createDummyVideoTrack() { const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); - + const frameWidth = 5; // Set the width of the frame const frameHeight = 5; // Set the height of the frame canvas.width = frameWidth; canvas.height = frameHeight; - + context.fillStyle = 'black'; context.fillRect(0, 0, frameWidth, frameHeight); - + const stream = canvas.captureStream(); const videoTrack = stream.getVideoTracks()[0]; - + return videoTrack; } @@ -111,7 +111,7 @@ export function start(pc, dc) { // add audio track navigator.mediaDevices.enumerateDevices() .then(function(devices) { - const hasAudioInput = devices.find((device) => { device.kind === "audioinput" }); + const hasAudioInput = devices.find((device) => device.kind === "audioinput"); var modifiedConstraints = {}; modifiedConstraints.video = constraints.video; modifiedConstraints.audio = hasAudioInput ? constraints.audio : false; @@ -143,7 +143,7 @@ export function start(pc, dc) { // const dummyMediaStream = new MediaStream(); // dummyMediaStream.addTrack(dummyVideoTrack); // pc.addTrack(dummyVideoTrack, dummyMediaStream); - + // setInterval(() => {pc.getStats(null).then((stats) => {stats.forEach((report) => console.log(report))})}, 10000) // var video = document.querySelector('video'); // var print = function (e, f){console.log(e, f); video.requestVideoFrameCallback(print);}; @@ -167,7 +167,7 @@ export function start(pc, dc) { var message = JSON.stringify({type: 'battery_level'}); dc.send(message); } - + dc.onopen = function() { dcInterval = setInterval(controlCommand, 50); batteryInterval = setInterval(batteryLevel, 10000); From ac471036fbc0818d802f235544767077d4f5151b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 1 Nov 2023 22:38:25 -0700 Subject: [PATCH 075/133] GM: update harness parts (#30361) GM harness parts --- docs/CARS.md | 10 +++++----- selfdrive/car/docs_definitions.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index a7eb0a120b0a699..eb7f88d7317423c 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -21,10 +21,10 @@ A supported vehicle is one that just works when you install a comma device. All |Cadillac|Escalade 2017[4](#footnotes)|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 OBD-II connector
- 1 comma 3X
- 2 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Cadillac|Escalade ESV 2016[4](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 OBD-II connector
- 1 comma 3X
- 2 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Cadillac|Escalade ESV 2019[4](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 OBD-II connector
- 1 comma 3X
- 2 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|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)](##)|
Parts- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|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)](##)|
Parts- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|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)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|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)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Chevrolet|Volt 2017-18[4](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 OBD-II connector
- 1 comma 3X
- 2 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |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)](##)|
Parts- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |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)](##)|
Parts- 1 FCA connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| @@ -50,7 +50,7 @@ A supported vehicle is one that just works when you install a comma device. All |Genesis|GV70 (3.5T Trim) 2022-23[6](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai M connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Genesis|GV80 2023[6](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai M connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |GMC|Acadia 2018[4](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 OBD-II connector
- 1 comma 3X
- 2 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |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)](##)|
Parts- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |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)](##)|
Parts- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index 880404feca86eda..2e80dde010302bc 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -114,7 +114,7 @@ class CarHarness(EnumBase): hyundai_r = BaseCarHarness("Hyundai R connector") custom = BaseCarHarness("Developer connector") obd_ii = BaseCarHarness("OBD-II connector", parts=[Cable.long_obdc_cable, Cable.long_obdc_cable], has_connector=False) - gm = BaseCarHarness("GM connector") + gm = BaseCarHarness("GM connector", parts=[Accessory.harness_box]) nissan_a = BaseCarHarness("Nissan A connector", parts=[Accessory.harness_box, Cable.rj45_cable_7ft, Cable.long_obdc_cable, Cable.usbc_coupler]) nissan_b = BaseCarHarness("Nissan B connector", parts=[Accessory.harness_box, Cable.rj45_cable_7ft, Cable.long_obdc_cable, Cable.usbc_coupler]) mazda = BaseCarHarness("Mazda connector") From 4c2bd853e4410db7f0d80e258291408e94c6c068 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Thu, 2 Nov 2023 14:01:00 -0700 Subject: [PATCH 076/133] =?UTF-8?q?(New)=20Lemon=20Pie=20Model=20?= =?UTF-8?q?=F0=9F=8D=8B=20(#30209)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 6f6e3749-1b7c-42e8-a33b-03929b7fc476/700 * oops deleted too much * 1b4308b7-a659-4ebd-b4c6-c81c1c3890f8/700 * 1be192f3-f407-4217-9757-78b9ad92750a/700 * remove some todos * more cleanup in lat planner * vego > min_speed * regen and update process replay refs * update model replay ref * update model replay ref commit again * Revert "update model replay ref commit again" This reverts commit 922cb796b8dfe264b0cce7a18206bb898b18bcb3. * update again * bump cereal --- cereal | 2 +- selfdrive/controls/lib/lateral_planner.py | 99 +++---------------- selfdrive/controls/plannerd.py | 4 +- selfdrive/modeld/constants.py | 2 + selfdrive/modeld/fill_model_msg.py | 5 + selfdrive/modeld/modeld.py | 5 + selfdrive/modeld/models/supercombo.onnx | 4 +- selfdrive/modeld/parse_model_outputs.py | 1 + .../process_replay/model_replay_ref_commit | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- .../test/process_replay/test_processes.py | 34 +++---- 11 files changed, 48 insertions(+), 112 deletions(-) diff --git a/cereal b/cereal index 24a522f6ba47aba..416c3d531c90ce1 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 24a522f6ba47aba12a9baea53020a8323673c79c +Subproject commit 416c3d531c90ce16498d782bf383625a857ee74c diff --git a/selfdrive/controls/lib/lateral_planner.py b/selfdrive/controls/lib/lateral_planner.py index 92786f73d82f502..2417eb3c68d8519 100644 --- a/selfdrive/controls/lib/lateral_planner.py +++ b/selfdrive/controls/lib/lateral_planner.py @@ -1,10 +1,4 @@ -import time import numpy as np -from openpilot.common.realtime import DT_MDL -from openpilot.common.numpy_fast import interp -from openpilot.system.swaglog import cloudlog -from openpilot.selfdrive.controls.lib.lateral_mpc_lib.lat_mpc import LateralMpc -from openpilot.selfdrive.controls.lib.lateral_mpc_lib.lat_mpc import N as LAT_MPC_N from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, MIN_SPEED, get_speed_error from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper import cereal.messaging as messaging @@ -13,18 +7,6 @@ TRAJECTORY_SIZE = 33 CAMERA_OFFSET = 0.04 - -PATH_COST = 1.0 -LATERAL_MOTION_COST = 0.11 -LATERAL_ACCEL_COST = 0.0 -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 = 700.0 - - class LateralPlanner: def __init__(self, CP, debug=False): self.DH = DesireHelper() @@ -37,42 +19,26 @@ def __init__(self, CP, debug=False): 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) - self.y_pts = np.zeros((TRAJECTORY_SIZE,)) self.v_plan = np.zeros((TRAJECTORY_SIZE,)) - self.v_ego = 0.0 + self.x_sol = np.zeros((TRAJECTORY_SIZE, 4), dtype=np.float32) + self.v_ego = MIN_SPEED self.l_lane_change_prob = 0.0 self.r_lane_change_prob = 0.0 self.debug_mode = debug - self.lat_mpc = LateralMpc() - self.reset_mpc(np.zeros(4)) - - def reset_mpc(self, x0=None): - if x0 is None: - x0 = np.zeros(4) - self.x0 = x0 - self.lat_mpc.reset(x0=self.x0) - def update(self, sm): - # clip speed , lateral planning is not possible at 0 speed - measured_curvature = sm['controlsState'].curvature v_ego_car = sm['carState'].vEgo # Parse model predictions md = sm['modelV2'] - if len(md.position.x) == TRAJECTORY_SIZE and len(md.orientation.x) == TRAJECTORY_SIZE: + if len(md.position.x) == TRAJECTORY_SIZE and len(md.velocity.x) == TRAJECTORY_SIZE and len(md.lateralPlannerSolution.x) == TRAJECTORY_SIZE: self.path_xyz = np.column_stack([md.position.x, md.position.y, md.position.z]) - 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) - get_speed_error(md, v_ego_car) self.v_plan = np.clip(car_speed, MIN_SPEED, np.inf) self.v_ego = self.v_plan[0] + self.x_sol = np.column_stack([md.lateralPlannerSolution.x, md.lateralPlannerSolution.y, md.lateralPlannerSolution.yaw, md.lateralPlannerSolution.yawRate]) # Lane change logic desire_state = md.meta.desireState @@ -82,66 +48,23 @@ def update(self, sm): lane_change_prob = self.l_lane_change_prob + self.r_lane_change_prob self.DH.update(sm['carState'], sm['carControl'].latActive, lane_change_prob) - self.lat_mpc.set_weights(PATH_COST, LATERAL_MOTION_COST, - LATERAL_ACCEL_COST, LATERAL_JERK_COST, - STEERING_RATE_COST) - - 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 = 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, - heading_pts, - yaw_rate_pts) - # init state for next iteration - # mpc.u_sol is the desired second derivative of psi given x0 curv state. - # with x0[3] = measured_yaw_rate, this would be the actual desired yaw rate. - # instead, interpolate x_sol so that x0[3] is the desired yaw rate for lat_control. - self.x0[3] = interp(DT_MDL, self.t_idxs[:LAT_MPC_N + 1], self.lat_mpc.x_sol[:, 3]) - - # Check for infeasible MPC solution - mpc_nans = np.isnan(self.lat_mpc.x_sol[:, 3]).any() - t = time.monotonic() - if mpc_nans or self.lat_mpc.solution_status != 0: - self.reset_mpc() - self.x0[3] = measured_curvature * self.v_ego - if t > self.last_cloudlog_t + 5.0: - self.last_cloudlog_t = t - cloudlog.warning("Lateral mpc - nan: True") - - if self.lat_mpc.cost > 1e6 or mpc_nans: - self.solution_invalid_cnt += 1 - else: - self.solution_invalid_cnt = 0 - def publish(self, sm, pm): - plan_solution_valid = self.solution_invalid_cnt < 2 plan_send = messaging.new_message('lateralPlan') plan_send.valid = sm.all_checks(service_list=['carState', 'controlsState', 'modelV2']) lateralPlan = plan_send.lateralPlan lateralPlan.modelMonoTime = sm.logMonoTime['modelV2'] - lateralPlan.dPathPoints = self.y_pts.tolist() - lateralPlan.psis = self.lat_mpc.x_sol[0:CONTROL_N, 2].tolist() + lateralPlan.dPathPoints = self.path_xyz[:,1].tolist() + lateralPlan.psis = self.x_sol[0:CONTROL_N, 2].tolist() - lateralPlan.curvatures = (self.lat_mpc.x_sol[0:CONTROL_N, 3]/self.v_ego).tolist() - lateralPlan.curvatureRates = [float(x.item() / self.v_ego) for x in self.lat_mpc.u_sol[0:CONTROL_N - 1]] + [0.0] + lateralPlan.curvatures = (self.x_sol[0:CONTROL_N, 3]/self.v_ego).tolist() + lateralPlan.curvatureRates = [float(0) for _ in range(CONTROL_N-1)] # TODO: unused - lateralPlan.mpcSolutionValid = bool(plan_solution_valid) - lateralPlan.solverExecutionTime = self.lat_mpc.solve_time + lateralPlan.mpcSolutionValid = bool(1) + lateralPlan.solverExecutionTime = 0.0 if self.debug_mode: - lateralPlan.solverCost = self.lat_mpc.cost lateralPlan.solverState = log.LateralPlan.SolverState.new_message() - lateralPlan.solverState.x = self.lat_mpc.x_sol.tolist() - lateralPlan.solverState.u = self.lat_mpc.u_sol.flatten().tolist() + lateralPlan.solverState.x = self.x_sol.tolist() lateralPlan.desire = self.DH.desire lateralPlan.useLaneLines = False diff --git a/selfdrive/controls/plannerd.py b/selfdrive/controls/plannerd.py index 1965bf858854119..15dbd4c5e2964c9 100755 --- a/selfdrive/controls/plannerd.py +++ b/selfdrive/controls/plannerd.py @@ -21,8 +21,8 @@ def publish_ui_plan(sm, pm, lateral_planner, longitudinal_planner): 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.x = np.interp(plan_odo, model_odo, lateral_planner.x_sol[:,0]).tolist() + uiPlan.position.y = np.interp(plan_odo, model_odo, lateral_planner.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) diff --git a/selfdrive/modeld/constants.py b/selfdrive/modeld/constants.py index e03d93d7e83c90f..4d3af51635ea413 100644 --- a/selfdrive/modeld/constants.py +++ b/selfdrive/modeld/constants.py @@ -21,6 +21,7 @@ class ModelConstants: NAV_FEATURE_LEN = 256 NAV_INSTRUCTION_LEN = 150 DRIVING_STYLE_LEN = 12 + LAT_PLANNER_STATE_LEN = 4 # model outputs constants FCW_THRESHOLDS_5MS2 = np.array([.05, .05, .15, .15, .15], dtype=np.float32) @@ -37,6 +38,7 @@ class ModelConstants: ROAD_EDGES_WIDTH = 2 PLAN_WIDTH = 15 DESIRE_PRED_WIDTH = 8 + LAT_PLANNER_SOLUTION_WIDTH = 4 NUM_LANE_LINES = 4 NUM_ROAD_EDGES = 2 diff --git a/selfdrive/modeld/fill_model_msg.py b/selfdrive/modeld/fill_model_msg.py index 55d7abc1aa004e6..2b8a72b9beb4aa0 100644 --- a/selfdrive/modeld/fill_model_msg.py +++ b/selfdrive/modeld/fill_model_msg.py @@ -71,6 +71,11 @@ def fill_model_msg(msg: capnp._DynamicStructBuilder, net_output_data: Dict[str, orientation_rate = modelV2.orientationRate fill_xyzt(orientation_rate, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ORIENTATION_RATE].T) + # lateral planning + solution = modelV2.lateralPlannerSolution + solution.x, solution.y, solution.yaw, solution.yawRate = [net_output_data['lat_planner_solution'][0,:,i].tolist() for i in range(4)] + solution.xStd, solution.yStd, solution.yawStd, solution.yawRateStd = [net_output_data['lat_planner_solution_stds'][0,:,i].tolist() for i in range(4)] + # times at X_IDXS according to model plan PLAN_T_IDXS = [np.nan] * ModelConstants.IDX_N PLAN_T_IDXS[0] = 0.0 diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index 4ad4038cbc79589..2b211b22e6945e0 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -11,6 +11,8 @@ from cereal.visionipc import VisionIpcClient, VisionStreamType, VisionBuf from openpilot.system.swaglog import cloudlog from openpilot.common.params import Params +from openpilot.common.realtime import DT_MDL +from openpilot.common.numpy_fast import interp from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.realtime import config_realtime_process from openpilot.common.transformations.model import get_warp_matrix @@ -54,6 +56,7 @@ def __init__(self, context: CLContext): self.inputs = { 'desire': np.zeros(ModelConstants.DESIRE_LEN * (ModelConstants.HISTORY_BUFFER_LEN+1), dtype=np.float32), 'traffic_convention': np.zeros(ModelConstants.TRAFFIC_CONVENTION_LEN, dtype=np.float32), + 'lat_planner_state': np.zeros(ModelConstants.LAT_PLANNER_STATE_LEN, dtype=np.float32), 'nav_features': np.zeros(ModelConstants.NAV_FEATURE_LEN, dtype=np.float32), 'nav_instructions': np.zeros(ModelConstants.NAV_INSTRUCTION_LEN, dtype=np.float32), 'features_buffer': np.zeros(ModelConstants.HISTORY_BUFFER_LEN * ModelConstants.FEATURE_LEN, dtype=np.float32), @@ -105,6 +108,8 @@ def run(self, buf: VisionBuf, wbuf: VisionBuf, transform: np.ndarray, transform_ self.inputs['features_buffer'][:-ModelConstants.FEATURE_LEN] = self.inputs['features_buffer'][ModelConstants.FEATURE_LEN:] self.inputs['features_buffer'][-ModelConstants.FEATURE_LEN:] = outputs['hidden_state'][0, :] + self.inputs['lat_planner_state'][2] = interp(DT_MDL, ModelConstants.T_IDXS, outputs['lat_planner_solution'][0, :, 2]) + self.inputs['lat_planner_state'][3] = interp(DT_MDL, ModelConstants.T_IDXS, outputs['lat_planner_solution'][0, :, 3]) return outputs diff --git a/selfdrive/modeld/models/supercombo.onnx b/selfdrive/modeld/models/supercombo.onnx index fcbbb2c1f576b4b..8325cc947e3cba5 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:18e53fa5d0f9a185833d50fa0d777725ca715460062f3a2c050847588525d87c -size 52272467 +oid sha256:6330383805f2e64e750f61c47660d2ec8522f55d84217c0520584d2e0d7c3faf +size 52939093 diff --git a/selfdrive/modeld/parse_model_outputs.py b/selfdrive/modeld/parse_model_outputs.py index a7b160fcea12289..9d37a5fad4ef1ad 100644 --- a/selfdrive/modeld/parse_model_outputs.py +++ b/selfdrive/modeld/parse_model_outputs.py @@ -93,6 +93,7 @@ def parse_outputs(self, outs: Dict[str, np.ndarray]) -> Dict[str, np.ndarray]: self.parse_mdn('wide_from_device_euler', outs, in_N=0, out_N=0, out_shape=(ModelConstants.WIDE_FROM_DEVICE_WIDTH,)) self.parse_mdn('lead', outs, in_N=ModelConstants.LEAD_MHP_N, out_N=ModelConstants.LEAD_MHP_SELECTION, out_shape=(ModelConstants.LEAD_TRAJ_LEN,ModelConstants.LEAD_WIDTH)) + self.parse_mdn('lat_planner_solution', outs, in_N=0, out_N=0, out_shape=(ModelConstants.IDX_N,ModelConstants.LAT_PLANNER_SOLUTION_WIDTH)) for k in ['lead_prob', 'lane_lines_prob', 'meta']: self.parse_binary_crossentropy(k, outs) self.parse_categorical_crossentropy('desire_state', outs, out_shape=(ModelConstants.DESIRE_PRED_WIDTH,)) diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index 2a4113a77fac308..1d8befbcaba21a6 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -0e0f55cf3bb2cf79b44adf190e6387a83deb6646 +eec02217169e6f5d71b8a376368ea96e83b10e4a diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index de54ba6e90ef13d..40ac91ee70752f6 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -6e27d5c97fe6554a86e9ee8bb9259e0cc6df5bb1 \ No newline at end of file +dbea36698ba48429b201b138846165eb4c329b92 \ 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 2baeaa8e52c9331..5429c9b63eb8326 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -41,23 +41,23 @@ ] segments = [ - ("BODY", "regen7FE9F3C7CE3|2023-10-25--23-56-32--0"), - ("HYUNDAI", "regen7519EF9EE71|2023-10-25--23-53-59--0"), - ("HYUNDAI2", "regenF68B9F1B286|2023-10-25--23-56-31--0"), - ("TOYOTA", "regen56DC072FA51|2023-10-25--23-53-51--0"), - ("TOYOTA2", "regen78130056536|2023-10-25--23-53-58--0"), - ("TOYOTA3", "regenC554B250909|2023-10-25--23-58-53--0"), - ("HONDA", "regen3ED625586FB|2023-10-25--23-56-29--0"), - ("HONDA2", "regen9F1A8F44FD5|2023-10-25--23-56-34--0"), - ("CHRYSLER", "regen60CE93181EA|2023-10-25--23-59-01--0"), - ("RAM", "regen9E2B62E8E9A|2023-10-26--00-00-41--0"), - ("SUBARU", "regenEEBF379E0ED|2023-10-26--00-01-37--0"), - ("GM", "regen0B0EE5D6E0D|2023-10-25--23-58-57--0"), - ("GM2", "regen043B44E4FBD|2023-10-26--00-03-51--0"), - ("NISSAN", "regen14F35E327BC|2023-10-26--00-01-22--0"), - ("VOLKSWAGEN", "regen63A052AE7D7|2023-10-26--00-01-36--0"), - ("MAZDA", "regenF9047685121|2023-10-26--00-05-02--0"), - ("FORD", "regen5115F2AE4FE|2023-10-26--00-06-17--0"), + ("BODY", "regen997DF2697CB|2023-10-30--23-14-29--0"), + ("HYUNDAI", "regen2A9D2A8E0B4|2023-10-30--23-13-34--0"), + ("HYUNDAI2", "regen6CA24BC3035|2023-10-30--23-14-28--0"), + ("TOYOTA", "regen5C019D76307|2023-10-30--23-13-31--0"), + ("TOYOTA2", "regen5DCADA88A96|2023-10-30--23-14-57--0"), + ("TOYOTA3", "regen7204CA3A498|2023-10-30--23-15-55--0"), + ("HONDA", "regen048F8FA0B24|2023-10-30--23-15-53--0"), + ("HONDA2", "regen7D2D3F82D5B|2023-10-30--23-15-55--0"), + ("CHRYSLER", "regen7125C42780C|2023-10-30--23-16-21--0"), + ("RAM", "regen2731F3213D2|2023-10-30--23-18-11--0"), + ("SUBARU", "regen86E4C1B4DDD|2023-10-30--23-18-14--0"), + ("GM", "regenF6393D64745|2023-10-30--23-17-18--0"), + ("GM2", "regen220F830C05B|2023-10-30--23-18-39--0"), + ("NISSAN", "regen4F671F7C435|2023-10-30--23-18-40--0"), + ("VOLKSWAGEN", "regen8BDFE7307A0|2023-10-30--23-19-36--0"), + ("MAZDA", "regen2E9F1A15FD5|2023-10-30--23-20-36--0"), + ("FORD", "regen6D39E54606E|2023-10-30--23-20-54--0"), ] # dashcamOnly makes don't need to be tested until a full port is done From 446f57040f983cb00ae3b99765100cb9a05054e7 Mon Sep 17 00:00:00 2001 From: JGO51810499 <123546095+JGO51810499@users.noreply.github.com> Date: Fri, 3 Nov 2023 05:35:22 +0800 Subject: [PATCH 077/133] Add missing LEXUS_RX_TSS2 FW (#30301) LEXUS RX 2020 dongle_id:b00aaa46833ddfa1 route_name:b00aaa46833ddfa1|2023-10-18--17-57-48--0 --- 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 f8fccb8d5b4a339..bac1fb84b92269e 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1937,6 +1937,7 @@ def match_fw_to_car_fuzzy(live_fw_versions) -> Set[str]: b'\x01896634D44000\x00\x00\x00\x00', b'\x018966348X0000\x00\x00\x00\x00', b'\x01896630ED5000\x00\x00\x00\x00', + b'\x018966348R9200\x00\x00\x00\x00', ], (Ecu.engine, 0x7e0, None): [ b'\x02348X4000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', @@ -1958,6 +1959,7 @@ def match_fw_to_car_fuzzy(live_fw_versions) -> Set[str]: b'F152648D60\x00\x00\x00\x00\x00\x00', b'F152648811\x00\x00\x00\x00\x00\x00', b'F152648C80\x00\x00\x00\x00\x00\x00', + b'F152648493\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B48261\x00\x00\x00\x00\x00\x00', From 676ba9f951456d6b38b9a08ad4386a53ede227b3 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Thu, 2 Nov 2023 19:07:30 -0400 Subject: [PATCH 078/133] Mapsd: test render performance (#30363) * cleanup and fix test * sa --------- Co-authored-by: Comma Device --- selfdrive/navd/tests/test_map_renderer.py | 56 +++++++++++++++++++---- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/selfdrive/navd/tests/test_map_renderer.py b/selfdrive/navd/tests/test_map_renderer.py index 1c3d8acd7fd8e95..75c6f76e42ae16f 100755 --- a/selfdrive/navd/tests/test_map_renderer.py +++ b/selfdrive/navd/tests/test_map_renderer.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import numpy as np import os import unittest import requests @@ -9,6 +10,7 @@ from typing import Any from cereal.visionipc import VisionIpcClient, VisionStreamType from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.hardware import TICI LLK_DECIMATION = 10 CACHE_PATH = "/data/mbgl-cache-navd.db" @@ -16,6 +18,11 @@ LOCATION1 = (32.7174, -117.16277) LOCATION2 = (32.7558, -117.2037) +DEFAULT_ITERATIONS = 30 * LLK_DECIMATION + +LOCATION1_REPEATED = [LOCATION1] * DEFAULT_ITERATIONS +LOCATION2_REPEATED = [LOCATION2] * DEFAULT_ITERATIONS + def gen_llk(location=LOCATION1): msg = messaging.new_message('liveLocationKalman') msg.liveLocationKalman.positionGeodetic = {'value': [*location, 0], 'std': [0., 0., 0.], 'valid': True} @@ -110,15 +117,14 @@ def _setup_test(self): assert self.vipc.connect(False) self.vipc.recv() - - def _run_test(self, expect_valid, location=LOCATION1): + def _run_test(self, expect_valid, locations=LOCATION1_REPEATED): starting_frame_id = None - self.location = location + render_times = [] # run test prev_frame_id = -1 - for i in range(30*LLK_DECIMATION): + for i, location in enumerate(locations): frame_expected = (i+1) % LLK_DECIMATION == 0 if self.sm.logMonoTime['mapRenderState'] == 0: @@ -131,7 +137,7 @@ def _run_test(self, expect_valid, location=LOCATION1): if starting_frame_id is None: starting_frame_id = prev_frame_id - llk = gen_llk(self.location) + llk = gen_llk(location) self.pm.send("liveLocationKalman", llk) self.pm.wait_for_readers_to_update("liveLocationKalman", 10) self.sm.update(1000 if frame_expected else 0) @@ -157,6 +163,7 @@ def _run_test(self, expect_valid, location=LOCATION1): assert self.sm['mapRenderState'].renderTime == 0. else: assert 0. < self.sm['mapRenderState'].renderTime < 0.1 + render_times.append(self.sm['mapRenderState'].renderTime) # check vision ipc output assert self.vipc.recv() is not None @@ -164,6 +171,8 @@ def _run_test(self, expect_valid, location=LOCATION1): assert self.vipc.timestamp_sof == llk.logMonoTime assert self.vipc.frame_id == self.sm['mapRenderState'].frameId + return render_times + def test_with_internet(self): self._setup_test() self._run_test(True) @@ -180,13 +189,42 @@ def test_recover_from_no_internet(self): self.server.disable_internet() # change locations to force mapsd to refetch - self._run_test(False, LOCATION2) + self._run_test(False, LOCATION2_REPEATED) self.server.enable_internet() - self._run_test(True, LOCATION2) + self._run_test(True, LOCATION2_REPEATED) + + self._run_test(True, LOCATION2_REPEATED) + + def test_render_time_distribution(self): + if not TICI: + raise unittest.SkipTest + + self._setup_test() + # from location1 -> location2 and back + locations = np.array([*np.linspace(LOCATION1, LOCATION2, 500), *np.linspace(LOCATION2, LOCATION1, 500)]).tolist() + + render_times = self._run_test(True, locations) + + _min = np.min(render_times) + _max = np.max(render_times) + _mean = np.mean(render_times) + _median = np.median(render_times) + _stddev = np.std(render_times) + + print(f"Stats: min: {_min}, max: {_max}, mean: {_mean}, median: {_median}, stddev: {_stddev}, count: {len(render_times)}") + + def assert_stat(stat, nominal, tol=0.2): + tol = (nominal / (1+tol)), (nominal * (1+tol)) + self.assertTrue(tol[0] < stat < tol[1], f"{stat} not in tolerance {tol}") + + assert_stat(_mean, 0.0035) + assert_stat(_median, 0.0034) + assert_stat(_stddev, 0.00093) + + self.assertLess(_max, 0.2) + self.assertGreater(_min, 0.0010) - self.location = LOCATION1 - self._run_test(True, LOCATION2) if __name__ == "__main__": unittest.main() From c52f2ec19b9d0cfc98aaa66b459d02f0d87116cb Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Thu, 2 Nov 2023 21:10:11 -0400 Subject: [PATCH 079/133] model_replay: allow skipping modeld/dmodeld (#30365) * skip model * sa --------- Co-authored-by: Comma Device --- selfdrive/test/process_replay/model_replay.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/selfdrive/test/process_replay/model_replay.py b/selfdrive/test/process_replay/model_replay.py index ca538ae160c70ce..2841386bf48c3ec 100755 --- a/selfdrive/test/process_replay/model_replay.py +++ b/selfdrive/test/process_replay/model_replay.py @@ -23,6 +23,7 @@ NAV_FRAMES = 50 NO_NAV = "NO_NAV" in os.environ +NO_MODEL = "NO_MODEL" in os.environ SEND_EXTRA_INPUTS = bool(int(os.getenv("SEND_EXTRA_INPUTS", "0"))) @@ -161,8 +162,10 @@ def do_GET(self): else: os.environ['MAPS_HOST'] = BASE_URL.rstrip('/') + log_msgs = [] # run replays - log_msgs = model_replay(lr, frs) + if not NO_MODEL: + log_msgs += model_replay(lr, frs) if not NO_NAV: log_msgs += nav_model_replay(lr) @@ -177,10 +180,11 @@ def do_GET(self): cmp_log = [] # logs are ordered based on type: modelV2, driverStateV2, nav messages (navThumbnail, mapRenderState, navModel) - model_start_index = next(i for i, m in enumerate(all_logs) if m.which() in ("modelV2", "cameraOdometry")) - cmp_log += all_logs[model_start_index:model_start_index + MAX_FRAMES*2] - dmon_start_index = next(i for i, m in enumerate(all_logs) if m.which() == "driverStateV2") - cmp_log += all_logs[dmon_start_index:dmon_start_index + MAX_FRAMES] + if not NO_MODEL: + model_start_index = next(i for i, m in enumerate(all_logs) if m.which() in ("modelV2", "cameraOdometry")) + cmp_log += all_logs[model_start_index:model_start_index + MAX_FRAMES*2] + dmon_start_index = next(i for i, m in enumerate(all_logs) if m.which() == "driverStateV2") + cmp_log += all_logs[dmon_start_index:dmon_start_index + MAX_FRAMES] if not NO_NAV: nav_start_index = next(i for i, m in enumerate(all_logs) if m.which() in ["navThumbnail", "mapRenderState", "navModel"]) nav_logs = all_logs[nav_start_index:nav_start_index + NAV_FRAMES*3] From bb828f0cda4af6a7a10d6e4375702cb07f58d51c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 2 Nov 2023 20:19:13 -0700 Subject: [PATCH 080/133] Revert "Mapsd: test render performance (#30363)" This reverts commit 676ba9f951456d6b38b9a08ad4386a53ede227b3. --- selfdrive/navd/tests/test_map_renderer.py | 56 ++++------------------- 1 file changed, 9 insertions(+), 47 deletions(-) diff --git a/selfdrive/navd/tests/test_map_renderer.py b/selfdrive/navd/tests/test_map_renderer.py index 75c6f76e42ae16f..1c3d8acd7fd8e95 100755 --- a/selfdrive/navd/tests/test_map_renderer.py +++ b/selfdrive/navd/tests/test_map_renderer.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import numpy as np import os import unittest import requests @@ -10,7 +9,6 @@ from typing import Any from cereal.visionipc import VisionIpcClient, VisionStreamType from openpilot.selfdrive.manager.process_config import managed_processes -from openpilot.system.hardware import TICI LLK_DECIMATION = 10 CACHE_PATH = "/data/mbgl-cache-navd.db" @@ -18,11 +16,6 @@ LOCATION1 = (32.7174, -117.16277) LOCATION2 = (32.7558, -117.2037) -DEFAULT_ITERATIONS = 30 * LLK_DECIMATION - -LOCATION1_REPEATED = [LOCATION1] * DEFAULT_ITERATIONS -LOCATION2_REPEATED = [LOCATION2] * DEFAULT_ITERATIONS - def gen_llk(location=LOCATION1): msg = messaging.new_message('liveLocationKalman') msg.liveLocationKalman.positionGeodetic = {'value': [*location, 0], 'std': [0., 0., 0.], 'valid': True} @@ -117,14 +110,15 @@ def _setup_test(self): assert self.vipc.connect(False) self.vipc.recv() - def _run_test(self, expect_valid, locations=LOCATION1_REPEATED): + + def _run_test(self, expect_valid, location=LOCATION1): starting_frame_id = None - render_times = [] + self.location = location # run test prev_frame_id = -1 - for i, location in enumerate(locations): + for i in range(30*LLK_DECIMATION): frame_expected = (i+1) % LLK_DECIMATION == 0 if self.sm.logMonoTime['mapRenderState'] == 0: @@ -137,7 +131,7 @@ def _run_test(self, expect_valid, locations=LOCATION1_REPEATED): if starting_frame_id is None: starting_frame_id = prev_frame_id - llk = gen_llk(location) + llk = gen_llk(self.location) self.pm.send("liveLocationKalman", llk) self.pm.wait_for_readers_to_update("liveLocationKalman", 10) self.sm.update(1000 if frame_expected else 0) @@ -163,7 +157,6 @@ def _run_test(self, expect_valid, locations=LOCATION1_REPEATED): assert self.sm['mapRenderState'].renderTime == 0. else: assert 0. < self.sm['mapRenderState'].renderTime < 0.1 - render_times.append(self.sm['mapRenderState'].renderTime) # check vision ipc output assert self.vipc.recv() is not None @@ -171,8 +164,6 @@ def _run_test(self, expect_valid, locations=LOCATION1_REPEATED): assert self.vipc.timestamp_sof == llk.logMonoTime assert self.vipc.frame_id == self.sm['mapRenderState'].frameId - return render_times - def test_with_internet(self): self._setup_test() self._run_test(True) @@ -189,42 +180,13 @@ def test_recover_from_no_internet(self): self.server.disable_internet() # change locations to force mapsd to refetch - self._run_test(False, LOCATION2_REPEATED) + self._run_test(False, LOCATION2) self.server.enable_internet() - self._run_test(True, LOCATION2_REPEATED) - - self._run_test(True, LOCATION2_REPEATED) - - def test_render_time_distribution(self): - if not TICI: - raise unittest.SkipTest - - self._setup_test() - # from location1 -> location2 and back - locations = np.array([*np.linspace(LOCATION1, LOCATION2, 500), *np.linspace(LOCATION2, LOCATION1, 500)]).tolist() - - render_times = self._run_test(True, locations) - - _min = np.min(render_times) - _max = np.max(render_times) - _mean = np.mean(render_times) - _median = np.median(render_times) - _stddev = np.std(render_times) - - print(f"Stats: min: {_min}, max: {_max}, mean: {_mean}, median: {_median}, stddev: {_stddev}, count: {len(render_times)}") - - def assert_stat(stat, nominal, tol=0.2): - tol = (nominal / (1+tol)), (nominal * (1+tol)) - self.assertTrue(tol[0] < stat < tol[1], f"{stat} not in tolerance {tol}") - - assert_stat(_mean, 0.0035) - assert_stat(_median, 0.0034) - assert_stat(_stddev, 0.00093) - - self.assertLess(_max, 0.2) - self.assertGreater(_min, 0.0010) + self._run_test(True, LOCATION2) + self.location = LOCATION1 + self._run_test(True, LOCATION2) if __name__ == "__main__": unittest.main() From a73412b39d1f3593c312c37b07cff6e842052433 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Thu, 2 Nov 2023 23:59:38 -0400 Subject: [PATCH 081/133] Cabana: fix wsl compilation (#30366) fix wsl --- tools/cabana/messageswidget.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index d51dae4142277e3..2452dcf21216914 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include From 0788573a735f78b40ce04767de285b768bb2ac1e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 2 Nov 2023 22:36:53 -0700 Subject: [PATCH 082/133] add lfs pull to setup instructions --- tools/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/README.md b/tools/README.md index a6889b769d738b6..315db3a75fbf5d3 100644 --- a/tools/README.md +++ b/tools/README.md @@ -26,6 +26,7 @@ git clone --recurse-submodules https://github.com/commaai/openpilot.git ``` bash cd openpilot +git lfs pull tools/ubuntu_setup.sh ``` From bf932c6277c25294857d68cf1a333ce9d151140c Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 3 Nov 2023 13:37:56 +0800 Subject: [PATCH 083/133] cabana: remove dependence on opendbc (#30329) * remove dependence on opendbc * move into function --- tools/cabana/SConscript | 10 +++----- tools/cabana/dbc/dbc.h | 2 -- tools/cabana/mainwin.cc | 25 ++++++++++--------- tools/cabana/mainwin.h | 3 +++ tools/cabana/tests/test_cabana.cc | 41 ------------------------------- 5 files changed, 20 insertions(+), 61 deletions(-) diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 46958f14e5986e3..d557b3af8093c0a 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -1,10 +1,7 @@ -import os -Import('env', 'qt_env', 'arch', 'common', 'messaging', 'visionipc', 'replay_lib', - 'cereal', 'transformations', 'widgets') +Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'replay_lib', 'cereal', 'widgets') base_frameworks = qt_env['FRAMEWORKS'] -base_libs = [common, messaging, cereal, visionipc, transformations, 'zmq', - 'capnp', 'kj', 'm', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"] +base_libs = [common, messaging, cereal, visionipc, 'qt_util', 'zmq', 'capnp', 'kj', 'm', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"] if arch == "Darwin": base_frameworks.append('OpenCL') @@ -18,8 +15,7 @@ else: qt_libs = ['qt_util'] + base_libs cabana_env = qt_env.Clone() -cabana_env["LIBPATH"] += ['../../opendbc/can'] -cabana_libs = [widgets, cereal, messaging, visionipc, replay_lib, 'panda', 'libdbc_static', 'avutil', 'avcodec', 'avformat', 'bz2', 'curl', 'yuv', 'usb-1.0'] + qt_libs +cabana_libs = [widgets, cereal, messaging, visionipc, replay_lib, 'panda', 'avutil', 'avcodec', 'avformat', 'bz2', 'curl', 'yuv', 'usb-1.0'] + qt_libs opendbc_path = '-DOPENDBC_FILE_PATH=\'"%s"\'' % (cabana_env.Dir("../../opendbc").abspath) cabana_env['CXXFLAGS'] += [opendbc_path] diff --git a/tools/cabana/dbc/dbc.h b/tools/cabana/dbc/dbc.h index bfb26c2842ed352..e07903e6807b48b 100644 --- a/tools/cabana/dbc/dbc.h +++ b/tools/cabana/dbc/dbc.h @@ -10,7 +10,6 @@ #include #include -#include "opendbc/can/common_dbc.h" const QString UNTITLED = "untitled"; const QString DEFAULT_NODE_NAME = "XXX"; @@ -120,5 +119,4 @@ class Msg { double get_raw_value(const uint8_t *data, size_t data_size, const cabana::Signal &sig); void updateMsbLsb(cabana::Signal &s); inline int flipBitPos(int start_bit) { return 8 * (start_bit / 8) + 7 - start_bit % 8; } -inline std::vector allDBCNames() { return get_dbc_names(); } inline QString doubleToString(double value) { return QString::number(value, 'g', std::numeric_limits::digits10); } diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 0053b08fd29bfe5..71e5ade9bb5cf5a 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,7 @@ #include "tools/replay/replay.h" MainWindow::MainWindow() : QMainWindow() { + loadFingerprints(); createDockWindows(); setCentralWidget(center_widget = new CenterWidget(this)); createActions(); @@ -56,12 +58,6 @@ MainWindow::MainWindow() : QMainWindow() { qInfo() << QString::fromStdString(msg); }); - // load fingerprints - QFile json_file(QApplication::applicationDirPath() + "/dbc/car_fingerprint_to_dbc.json"); - if (json_file.open(QIODevice::ReadOnly)) { - fingerprint_to_dbc = QJsonDocument::fromJson(json_file.readAll()); - } - setStyleSheet(QString(R"(QMainWindow::separator { width: %1px; /* when vertical */ height: %1px; /* when horizontal */ @@ -77,6 +73,16 @@ MainWindow::MainWindow() : QMainWindow() { QObject::connect(StreamNotifier::instance(), &StreamNotifier::streamStarted, this, &MainWindow::streamStarted); } +void MainWindow::loadFingerprints() { + QFile json_file(QApplication::applicationDirPath() + "/dbc/car_fingerprint_to_dbc.json"); + if (json_file.open(QIODevice::ReadOnly)) { + fingerprint_to_dbc = QJsonDocument::fromJson(json_file.readAll()); + auto dbc_names = fingerprint_to_dbc.object().toVariantMap().values(); + std::transform(dbc_names.begin(), dbc_names.end(), std::inserter(opendbc_names, opendbc_names.begin()), + [](const auto &name) { return name.toString(); }); + } +} + void MainWindow::createActions() { // File menu QMenu *file_menu = menuBar()->addMenu(tr("&File")); @@ -102,11 +108,8 @@ 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 = allDBCNames(); - std::sort(dbc_names.begin(), dbc_names.end()); - for (const auto &name : dbc_names) { - QString dbc_name = QString::fromStdString(name); - load_opendbc_menu->addAction(dbc_name, [=]() { loadDBCFromOpendbc(dbc_name); }); + for (const auto &dbc_name : opendbc_names) { + load_opendbc_menu->addAction(dbc_name, [this, name = dbc_name]() { loadDBCFromOpendbc(name); }); } file_menu->addAction(tr("Load DBC From Clipboard"), [=]() { loadFromClipboard(); }); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index bbbe8730cb7c671..2b1c99127192093 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "tools/cabana/chart/chartswidget.h" #include "tools/cabana/dbc/dbcmanager.h" @@ -50,6 +51,7 @@ public slots: void saveFile(DBCFile *dbc_file); void saveFileAs(DBCFile *dbc_file); void saveFileToClipboard(DBCFile *dbc_file); + void loadFingerprints(); void loadFromClipboard(SourceSet s = SOURCE_ALL, bool close_all = true); void autoSave(); void cleanupAutoSaveFile(); @@ -84,6 +86,7 @@ public slots: QProgressBar *progress_bar; QLabel *status_label; QJsonDocument fingerprint_to_dbc; + std::set opendbc_names; QSplitter *video_splitter = nullptr; enum { MAX_RECENT_FILES = 15 }; QAction *recent_files_acts[MAX_RECENT_FILES] = {}; diff --git a/tools/cabana/tests/test_cabana.cc b/tools/cabana/tests/test_cabana.cc index 791dfd1329eceec..f6884a2dc990f99 100644 --- a/tools/cabana/tests/test_cabana.cc +++ b/tools/cabana/tests/test_cabana.cc @@ -1,5 +1,4 @@ -#include "opendbc/can/common.h" #undef INFO #include "catch2/catch.hpp" #include "tools/replay/logreader.h" @@ -29,46 +28,6 @@ TEST_CASE("DBCFile::generateDBC") { } } -TEST_CASE("Parse can messages") { - DBCManager dbc(nullptr); - dbc.open({0}, "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({.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); - values_1[{c.getAddress(), sig->name}].push_back(val); - } - } - } - - can_parser.UpdateCans(e->mono_time, e->event.getCan()); - std::vector values_2; - can_parser.query_latest(values_2); - for (auto &[key, v1] : values_1) { - bool found = false; - for (auto &v2 : values_2) { - 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; - break; - } - } - REQUIRE(found); - } - } - } -} - TEST_CASE("parse_dbc") { QString content = R"( BO_ 160 message_1: 8 EON From 983ac6c235d2ecf770d53481aaea707899db4c4b Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Fri, 3 Nov 2023 13:59:07 -0400 Subject: [PATCH 084/133] Mapsd: test render performance (#30367) * cleanup and fix test * sa * fix test failing * increase tolerance more for stddev * increase that more --------- Co-authored-by: Comma Device --- selfdrive/navd/tests/test_map_renderer.py | 56 +++++++++++++++++++---- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/selfdrive/navd/tests/test_map_renderer.py b/selfdrive/navd/tests/test_map_renderer.py index 1c3d8acd7fd8e95..b9cf42824ecc77d 100755 --- a/selfdrive/navd/tests/test_map_renderer.py +++ b/selfdrive/navd/tests/test_map_renderer.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import numpy as np import os import unittest import requests @@ -9,6 +10,7 @@ from typing import Any from cereal.visionipc import VisionIpcClient, VisionStreamType from openpilot.selfdrive.manager.process_config import managed_processes +from openpilot.system.hardware import TICI LLK_DECIMATION = 10 CACHE_PATH = "/data/mbgl-cache-navd.db" @@ -16,6 +18,11 @@ LOCATION1 = (32.7174, -117.16277) LOCATION2 = (32.7558, -117.2037) +DEFAULT_ITERATIONS = 30 * LLK_DECIMATION + +LOCATION1_REPEATED = [LOCATION1] * DEFAULT_ITERATIONS +LOCATION2_REPEATED = [LOCATION2] * DEFAULT_ITERATIONS + def gen_llk(location=LOCATION1): msg = messaging.new_message('liveLocationKalman') msg.liveLocationKalman.positionGeodetic = {'value': [*location, 0], 'std': [0., 0., 0.], 'valid': True} @@ -110,15 +117,14 @@ def _setup_test(self): assert self.vipc.connect(False) self.vipc.recv() - - def _run_test(self, expect_valid, location=LOCATION1): + def _run_test(self, expect_valid, locations=LOCATION1_REPEATED): starting_frame_id = None - self.location = location + render_times = [] # run test prev_frame_id = -1 - for i in range(30*LLK_DECIMATION): + for i, location in enumerate(locations): frame_expected = (i+1) % LLK_DECIMATION == 0 if self.sm.logMonoTime['mapRenderState'] == 0: @@ -131,7 +137,7 @@ def _run_test(self, expect_valid, location=LOCATION1): if starting_frame_id is None: starting_frame_id = prev_frame_id - llk = gen_llk(self.location) + llk = gen_llk(location) self.pm.send("liveLocationKalman", llk) self.pm.wait_for_readers_to_update("liveLocationKalman", 10) self.sm.update(1000 if frame_expected else 0) @@ -157,6 +163,7 @@ def _run_test(self, expect_valid, location=LOCATION1): assert self.sm['mapRenderState'].renderTime == 0. else: assert 0. < self.sm['mapRenderState'].renderTime < 0.1 + render_times.append(self.sm['mapRenderState'].renderTime) # check vision ipc output assert self.vipc.recv() is not None @@ -164,6 +171,8 @@ def _run_test(self, expect_valid, location=LOCATION1): assert self.vipc.timestamp_sof == llk.logMonoTime assert self.vipc.frame_id == self.sm['mapRenderState'].frameId + return render_times + def test_with_internet(self): self._setup_test() self._run_test(True) @@ -180,13 +189,42 @@ def test_recover_from_no_internet(self): self.server.disable_internet() # change locations to force mapsd to refetch - self._run_test(False, LOCATION2) + self._run_test(False, LOCATION2_REPEATED) self.server.enable_internet() - self._run_test(True, LOCATION2) + self._run_test(True, LOCATION2_REPEATED) + + self._run_test(True, LOCATION2_REPEATED) + + def test_render_time_distribution(self): + if not TICI: + raise unittest.SkipTest + + self._setup_test() + # from location1 -> location2 and back + locations = np.array([*np.linspace(LOCATION1, LOCATION2, 2000), *np.linspace(LOCATION2, LOCATION1, 2000)]).tolist() + + render_times = self._run_test(True, locations) + + _min = np.min(render_times) + _max = np.max(render_times) + _mean = np.mean(render_times) + _median = np.median(render_times) + _stddev = np.std(render_times) + + print(f"Stats: min: {_min}, max: {_max}, mean: {_mean}, median: {_median}, stddev: {_stddev}, count: {len(render_times)}") + + def assert_stat(stat, nominal, tol=0.3): + tol = (nominal / (1+tol)), (nominal * (1+tol)) + self.assertTrue(tol[0] < stat < tol[1], f"{stat} not in tolerance {tol}") + + assert_stat(_mean, 0.0035) + assert_stat(_median, 0.0034) + assert_stat(_stddev, 0.00093, tol=0.5) + + self.assertLess(_max, 0.2) + self.assertGreater(_min, 0.0010) - self.location = LOCATION1 - self._run_test(True, LOCATION2) if __name__ == "__main__": unittest.main() From a46544f7084593d028ab0c202783125fa833cc79 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 4 Nov 2023 02:16:48 +0800 Subject: [PATCH 085/133] cabana/sparkline: Fix "Painter not active" warning (#30370) fix painter not active --- tools/cabana/chart/sparkline.cc | 55 ++++++++++----------------------- tools/cabana/chart/sparkline.h | 17 ++++------ tools/cabana/signalview.cc | 17 +++------- 3 files changed, 28 insertions(+), 61 deletions(-) diff --git a/tools/cabana/chart/sparkline.cc b/tools/cabana/chart/sparkline.cc index 1ae6a1bfe090422..42608c030f4b263 100644 --- a/tools/cabana/chart/sparkline.cc +++ b/tools/cabana/chart/sparkline.cc @@ -1,5 +1,6 @@ #include "tools/cabana/chart/sparkline.h" +#include #include #include @@ -12,52 +13,30 @@ void Sparkline::update(const MessageId &msg_id, const cabana::Signal *sig, doubl auto first = std::lower_bound(msgs.cbegin(), msgs.cend(), first_ts, CompareCanEvent()); auto last = std::upper_bound(first, msgs.cend(), ts, CompareCanEvent()); - bool update_values = last_ts != last_msg_ts || time_range != range; - last_ts = last_msg_ts; - time_range = range; - - if (first != last) { - if (update_values) { - values.clear(); - if (values.capacity() < std::distance(first, last)) { - values.reserve(std::distance(first, last) * 2); - } - min_val = std::numeric_limits::max(); - max_val = std::numeric_limits::lowest(); - for (auto it = first; it != last; ++it) { - const CanEvent *e = *it; - double value = 0; - if (sig->getValue(e->dat, e->size, &value)) { - values.emplace_back((e->mono_time - (*first)->mono_time) / 1e9, value); - if (min_val > value) min_val = value; - if (max_val < value) max_val = value; - } - } - if (min_val == max_val) { - min_val -= 1; - max_val += 1; + if (first != last && !size.isEmpty()) { + points.clear(); + double value = 0; + for (auto it = first; it != last; ++it) { + if (sig->getValue((*it)->dat, (*it)->size, &value)) { + points.emplace_back(((*it)->mono_time - (*first)->mono_time) / 1e9, value); } } - } else { - values.clear(); - } - - if (!values.empty()) { - render(sig->color, size); + const auto [min, max] = std::minmax_element(points.begin(), points.end(), + [](auto &l, auto &r) { return l.y() < r.y(); }); + min_val = min->y() == max->y() ? min->y() - 1 : min->y(); + max_val = min->y() == max->y() ? max->y() + 1 : max->y(); + freq_ = points.size() / std::max(points.back().x() - points.front().x(), 1.0); + render(sig->color, range, size); } else { pixmap = QPixmap(); - min_val = -1; - max_val = 1; } } -void Sparkline::render(const QColor &color, QSize size) { - const double xscale = (size.width() - 1) / (double)time_range; +void Sparkline::render(const QColor &color, int range, QSize size) { + const double xscale = (size.width() - 1) / (double)range; const double yscale = (size.height() - 3) / (max_val - min_val); - points.clear(); - points.reserve(values.capacity()); - for (auto &v : values) { - points.emplace_back(v.x() * xscale, 1 + std::abs(v.y() - max_val) * yscale); + for (auto &v : points) { + v = QPoint(v.x() * xscale, 1 + std::abs(v.y() - max_val) * yscale); } qreal dpr = qApp->devicePixelRatio(); diff --git a/tools/cabana/chart/sparkline.h b/tools/cabana/chart/sparkline.h index 21cbd40a3ff8b50..3bdd8a3ee526378 100644 --- a/tools/cabana/chart/sparkline.h +++ b/tools/cabana/chart/sparkline.h @@ -1,29 +1,24 @@ #pragma once -#include - #include #include #include -#include "tools/cabana/dbc/dbcmanager.h" +#include "tools/cabana/dbc/dbc.h" class Sparkline { public: void update(const MessageId &msg_id, const cabana::Signal *sig, double last_msg_ts, int range, QSize size); - const QSize size() const { return pixmap.size() / pixmap.devicePixelRatio(); } - inline double freq() const { - return values.empty() ? 0 : values.size() / std::max(values.back().x() - values.front().x(), 1.0); - } + inline double freq() const { return freq_; } + bool isEmpty() const { return pixmap.isNull(); } QPixmap pixmap; double min_val = 0; double max_val = 0; - double last_ts = 0; - int time_range = 0; private: - void render(const QColor &color, QSize size); - std::vector values; + void render(const QColor &color, int range, QSize size); + std::vector points; + double freq_ = 0; }; diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 3abcf4d11128350..7eb647b65036b45 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -351,7 +351,7 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->setPen(option.palette.color(option.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text)); QRect rect = r.adjusted(sparkline_size.width() + 1, 0, 0, 0); int value_adjust = 10; - if (item->highlight || option.state & QStyle::State_Selected) { + if (!item->sparkline.isEmpty() && (item->highlight || option.state & QStyle::State_Selected)) { painter->drawLine(rect.topLeft(), rect.bottomLeft()); rect.adjust(5, -v_margin, 0, v_margin); painter->setFont(minmax_font); @@ -361,7 +361,7 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->drawText(rect, Qt::AlignLeft | Qt::AlignBottom, min); QFontMetrics fm(minmax_font); value_adjust = std::max(fm.width(min), fm.width(max)) + 5; - } else if (item->sig->type == cabana::Signal::Type::Multiplexed) { + } else if (!item->sparkline.isEmpty() && item->sig->type == cabana::Signal::Type::Multiplexed) { // display freq of multiplexed signal painter->setFont(label_font); QString freq = QString("%1 hz").arg(item->sparkline.freq(), 0, 'g', 2); @@ -610,12 +610,8 @@ void SignalView::handleSignalAdded(MessageId id, const cabana::Signal *sig) { } void SignalView::handleSignalUpdated(const cabana::Signal *sig) { - if (int row = model->signalRow(sig); row != -1) { - auto item = model->getItem(model->index(row, 1)); - // invalidate the sparkline - item->sparkline.last_ts = 0; + if (int row = model->signalRow(sig); row != -1) updateState(); - } } void SignalView::updateState(const std::set *msgs) { @@ -648,11 +644,8 @@ void SignalView::updateState(const std::set *msgs) { QFutureSynchronizer synchronizer; for (int i = first_visible_row; i <= last_visible_row; ++i) { auto item = model->getItem(model->index(i, 1)); - auto &s = item->sparkline; - if (s.last_ts != last_msg.ts || s.size() != size || s.time_range != settings.sparkline_range) { - synchronizer.addFuture(QtConcurrent::run( - &s, &Sparkline::update, model->msg_id, item->sig, last_msg.ts, settings.sparkline_range, size)); - } + synchronizer.addFuture(QtConcurrent::run( + &item->sparkline, &Sparkline::update, model->msg_id, item->sig, last_msg.ts, settings.sparkline_range, size)); } } From f5279284f5b4d993a181e8ba2d9a6ec7985130d5 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 4 Nov 2023 02:16:58 +0800 Subject: [PATCH 086/133] cabana: fix QChart leak (#30369) fix QChart leak --- tools/cabana/chart/chart.cc | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/tools/cabana/chart/chart.cc b/tools/cabana/chart/chart.cc index dee7cc524884e84..28d122576cccb53 100644 --- a/tools/cabana/chart/chart.cc +++ b/tools/cabana/chart/chart.cc @@ -25,20 +25,18 @@ const int AXIS_X_TOP_MARGIN = 4; static inline bool xLessThan(const QPointF &p, float x) { return p.x() < x; } ChartView::ChartView(const std::pair &x_range, ChartsWidget *parent) - : charts_widget(parent), tip_label(this), QChartView(nullptr, parent) { + : charts_widget(parent), tip_label(this), QChartView(parent) { series_type = (SeriesType)settings.chart_series_type; - QChart *chart = new QChart(); - chart->setBackgroundVisible(false); + chart()->setBackgroundVisible(false); axis_x = new QValueAxis(this); axis_y = new QValueAxis(this); - chart->addAxis(axis_x, Qt::AlignBottom); - chart->addAxis(axis_y, Qt::AlignLeft); - chart->legend()->layout()->setContentsMargins(0, 0, 0, 0); - chart->legend()->setShowToolTips(true); - chart->setMargins({0, 0, 0, 0}); + chart()->addAxis(axis_x, Qt::AlignBottom); + chart()->addAxis(axis_y, Qt::AlignLeft); + chart()->legend()->layout()->setContentsMargins(0, 0, 0, 0); + chart()->legend()->setShowToolTips(true); + chart()->setMargins({0, 0, 0, 0}); axis_x->setRange(x_range.first, x_range.second); - setChart(chart); createToolButtons(); setRubberBand(QChartView::HorizontalRubberBand); From fb3c0934d85d6a056643b2792852884b43fbdd3c Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 4 Nov 2023 22:07:45 +0800 Subject: [PATCH 087/133] ui/body.cc: fix QMovie leak (#30379) fix QMovie leak --- selfdrive/ui/qt/body.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/ui/qt/body.cc b/selfdrive/ui/qt/body.cc index f2628d304f36b5a..e01adbe06378114 100644 --- a/selfdrive/ui/qt/body.cc +++ b/selfdrive/ui/qt/body.cc @@ -63,9 +63,9 @@ BodyWindow::BodyWindow(QWidget *parent) : fuel_filter(1.0, 5., 1. / UI_FREQ), QW face = new QLabel(); face->setAlignment(Qt::AlignCenter); layout->addWidget(face); - awake = new QMovie("../assets/body/awake.gif"); + awake = new QMovie("../assets/body/awake.gif", {}, this); awake->setCacheMode(QMovie::CacheAll); - sleep = new QMovie("../assets/body/sleep.gif"); + sleep = new QMovie("../assets/body/sleep.gif", {}, this); sleep->setCacheMode(QMovie::CacheAll); // record button From 240f43b42166effa179494b5502ca7f5a18981a2 Mon Sep 17 00:00:00 2001 From: Stephen Marin Date: Sun, 5 Nov 2023 01:04:54 -0400 Subject: [PATCH 088/133] Subaru: Fingerprint for 2021 Outback XT (#30380) * Fingerprint for 2021 Outback XT * that one already exists --------- Co-authored-by: Justin Newberry --- 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 1c9299e6b69b7d3..5f59eb3f4cbab9b 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -628,6 +628,7 @@ def init_make(self, CP: car.CarParams): b'\xbc"`q\x07', b'\xe3,\xa0@\x07', b'\xbc,\xa0u\x07', + b'\xde,\xa0@\x07', ], (Ecu.transmission, 0x7e1, None): [ b'\xa5\xfe\xf7@\x00', From b791c0296b5a57ab031cbae924446ec732eecb9f Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Sun, 5 Nov 2023 01:09:43 -0400 Subject: [PATCH 089/133] Subaru: 2016 legacy fingerprint (#30386) legacy fw --- selfdrive/car/subaru/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 5f59eb3f4cbab9b..cb56327f0990ef5 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -470,6 +470,7 @@ def init_make(self, CP: car.CarParams): b'[\xba\xc4\x03', b'{\x97D\x00', b'[\x97D\000', + b'k\x9aD\x00', ], (Ecu.eps, 0x746, None): [ b'[\xb0\x00\x01', @@ -486,12 +487,14 @@ def init_make(self, CP: car.CarParams): b'\xa0+@p\x07', b'\xb4"@0\x07', b'\xa0"@q\a', + b'\xab+@p\x07', ], (Ecu.transmission, 0x7e1, None): [ b'\xbe\xf2\x00p\x00', b'\xbf\xfb\xc0\x80\x00', b'\xbd\xf2\x00`\x00', b'\xbf\xf2\000\x80\000', + b'\xbe\xfb\xc0p\x00', ], }, CAR.OUTBACK_PREGLOBAL: { From 1463fd3917a9aa3ba556e82e411935eecb959ab6 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Sun, 5 Nov 2023 01:31:09 -0400 Subject: [PATCH 090/133] Subaru: 2015 outback fingerprint (#30387) subaru outback fw --- 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 cb56327f0990ef5..3e3046ebd300606 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -538,6 +538,7 @@ def init_make(self, CP: car.CarParams): b'\xb4"@r\a', b'\xa0+@@\x07', b'\xa0\"@\x80\a', + b'\xa0*@u\x07', ], (Ecu.transmission, 0x7e1, None): [ b'\xbd\xfb\xe0\x80\x00', From 0fbc36bce19a7fb7a57484488bed16f07a51c888 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Sun, 5 Nov 2023 03:21:46 -0500 Subject: [PATCH 091/133] Subaru: forester 2017 fingerprint (#30388) forester fw --- selfdrive/car/subaru/values.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 3e3046ebd300606..59dfc701dfa87d1 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -439,6 +439,7 @@ def init_make(self, CP: car.CarParams): (Ecu.abs, 0x7b0, None): [ b'\x7d\x97\x14\x40', b'\xf1\x00\xbb\x0c\x04', + b'm\x97\x14@', ], (Ecu.eps, 0x746, None): [ b'}\xc0\x10\x00', @@ -447,13 +448,15 @@ def init_make(self, CP: car.CarParams): (Ecu.fwdCamera, 0x787, None): [ b'\x00\x00\x64\x35\x1f\x40\x20\x09', b'\x00\x00c\xe9\x1f@ \x03', - b'\x00\x00d\xd3\x1f@ \t' + b'\x00\x00d\xd3\x1f@ \t', + b'\x00\x00c\xe9\x00\x00\x00\x00', ], (Ecu.engine, 0x7e0, None): [ b'\xba"@p\a', b'\xa7)\xa0q\a', b'\xf1\x82\xa7)\xa0q\a', b'\xba"@@\a', + b'\xa7"@p\x07', ], (Ecu.transmission, 0x7e1, None): [ b'\xdc\xf2\x60\x60\x00', @@ -462,6 +465,7 @@ def init_make(self, CP: car.CarParams): b'\xdc\xf2`\x81\000', b'\xdc\xf2`\x80\x00', b'\x1a\xf6F`\x00', + b'\xda\xf2`\x80\x00', ], }, CAR.LEGACY_PREGLOBAL: { From df79ec531497cec5c8fd7063790787f3ebd2e3f4 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Sun, 5 Nov 2023 20:53:42 -0500 Subject: [PATCH 092/133] Subaru: improve longitudinal tuning (#30389) subaru long tuning --- selfdrive/car/subaru/values.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 59dfc701dfa87d1..618d78ae0557b2b 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -43,13 +43,13 @@ def __init__(self, CP): RPM_INACTIVE = 600 # a good base rpm for zero acceleration - THROTTLE_LOOKUP_BP = [0, 1] + THROTTLE_LOOKUP_BP = [0, 2] THROTTLE_LOOKUP_V = [THROTTLE_INACTIVE, THROTTLE_MAX] - RPM_LOOKUP_BP = [0, 1] + RPM_LOOKUP_BP = [0, 2] RPM_LOOKUP_V = [RPM_INACTIVE, RPM_MAX] - BRAKE_LOOKUP_BP = [-1, 0] + BRAKE_LOOKUP_BP = [-3.5, 0] BRAKE_LOOKUP_V = [BRAKE_MAX, BRAKE_MIN] From bdf2fa0f83d92c67c3fc90972ca1d71af543fc1a Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Mon, 6 Nov 2023 12:04:53 -0500 Subject: [PATCH 093/133] Mapsd: move on the CPU (#30349) * mapsd -> cpu * link directly to mesa * Fix gitignore * without launcher script * dont change that * dont need that * add to files_common * rename to configure cpu rendering * without a symlink! * update time refs * update ref * update ref * remove duplicate include * bump up again --------- Co-authored-by: Comma Device --- selfdrive/navd/SConscript | 2 +- selfdrive/navd/main.cc | 5 ++++ selfdrive/navd/tests/test_map_renderer.py | 27 +++++++------------ .../process_replay/model_replay_ref_commit | 2 +- selfdrive/test/test_onroad.py | 4 +-- system/hardware/base.h | 2 ++ system/hardware/pc/hardware.h | 5 ++++ system/hardware/tici/hardware.h | 5 ++++ 8 files changed, 31 insertions(+), 21 deletions(-) diff --git a/selfdrive/navd/SConscript b/selfdrive/navd/SConscript index d1db79506a695cc..c116ef1535bd78c 100644 --- a/selfdrive/navd/SConscript +++ b/selfdrive/navd/SConscript @@ -4,7 +4,7 @@ map_env = qt_env.Clone() libs = ['qt_widgets', 'qt_util', 'qmapboxgl', common, messaging, cereal, visionipc, transformations, 'zmq', 'capnp', 'kj', 'm', 'OpenCL', 'ssl', 'crypto', 'pthread', 'json11'] + map_env["LIBS"] if arch == 'larch64': - libs.append('EGL') + libs.append(':libEGL_mesa.so.0') if arch in ['larch64', 'aarch64', 'x86_64']: if arch == 'x86_64': diff --git a/selfdrive/navd/main.cc b/selfdrive/navd/main.cc index f8501bf4a5a0c93..5251b046fbebfb3 100644 --- a/selfdrive/navd/main.cc +++ b/selfdrive/navd/main.cc @@ -4,14 +4,19 @@ #include #include +#include "common/util.h" #include "selfdrive/ui/qt/util.h" #include "selfdrive/ui/qt/maps/map_helpers.h" #include "selfdrive/navd/map_renderer.h" #include "system/hardware/hw.h" int main(int argc, char *argv[]) { + Hardware::config_cpu_rendering(); + qInstallMessageHandler(swagLogMessageHandler); setpriority(PRIO_PROCESS, 0, -20); + int ret = util::set_core_affinity({0, 1, 2, 3}); + assert(ret == 0); QApplication app(argc, argv); std::signal(SIGINT, sigTermHandler); diff --git a/selfdrive/navd/tests/test_map_renderer.py b/selfdrive/navd/tests/test_map_renderer.py index b9cf42824ecc77d..c4c9785cb16f383 100755 --- a/selfdrive/navd/tests/test_map_renderer.py +++ b/selfdrive/navd/tests/test_map_renderer.py @@ -34,19 +34,12 @@ def gen_llk(location=LOCATION1): class MapBoxInternetDisabledRequestHandler(http.server.BaseHTTPRequestHandler): INTERNET_ACTIVE = True - def setup(self): - if self.INTERNET_ACTIVE: - super().setup() - - def handle(self): - if self.INTERNET_ACTIVE: - super().handle() - - def finish(self): - if self.INTERNET_ACTIVE: - super().finish() - def do_GET(self): + if not self.INTERNET_ACTIVE: + self.send_response(500) + self.end_headers() + return + url = f'https://api.mapbox.com{self.path}' headers = dict(self.headers) @@ -218,12 +211,12 @@ def assert_stat(stat, nominal, tol=0.3): tol = (nominal / (1+tol)), (nominal * (1+tol)) self.assertTrue(tol[0] < stat < tol[1], f"{stat} not in tolerance {tol}") - assert_stat(_mean, 0.0035) - assert_stat(_median, 0.0034) - assert_stat(_stddev, 0.00093, tol=0.5) + assert_stat(_mean, 0.030) + assert_stat(_median, 0.027) + assert_stat(_stddev, 0.0078) - self.assertLess(_max, 0.2) - self.assertGreater(_min, 0.0010) + self.assertLess(_max, 0.065) + self.assertGreater(_min, 0.015) if __name__ == "__main__": diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index 1d8befbcaba21a6..2785ca71a1e94e4 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -eec02217169e6f5d71b8a376368ea96e83b10e4a +ca18755cd1a1bc28c06e85a280d79d7e48a8438c diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 841c77f142a45f8..30632c7cd6c248d 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -33,7 +33,7 @@ "./encoderd": 17.0, "./camerad": 14.5, "./locationd": 11.0, - "./mapsd": 2.0, + "./mapsd": 1.5, "selfdrive.controls.plannerd": 16.5, "./_ui": 18.0, "selfdrive.locationd.paramsd": 9.0, @@ -301,7 +301,7 @@ def test_memory_usage(self): self.assertLessEqual(max(mems) - min(mems), 3.0) def test_gpu_usage(self): - self.assertEqual(self.gpu_procs, {"weston", "_ui", "mapsd", "camerad", "selfdrive.modeld.modeld"}) + self.assertEqual(self.gpu_procs, {"weston", "_ui", "camerad", "selfdrive.modeld.modeld"}) def test_camera_processing_time(self): result = "\n" diff --git a/system/hardware/base.h b/system/hardware/base.h index d86b3168438c66f..43f5db023df89af 100644 --- a/system/hardware/base.h +++ b/system/hardware/base.h @@ -34,6 +34,8 @@ class HardwareNone { static bool get_ssh_enabled() { return false; } static void set_ssh_enabled(bool enabled) {} + static void config_cpu_rendering(); + static bool PC() { return false; } static bool TICI() { return false; } static bool AGNOS() { return false; } diff --git a/system/hardware/pc/hardware.h b/system/hardware/pc/hardware.h index 5cd825d61d79a9b..63244c5c5db3052 100644 --- a/system/hardware/pc/hardware.h +++ b/system/hardware/pc/hardware.h @@ -20,4 +20,9 @@ class HardwarePC : public HardwareNone { snprintf(volume_str, sizeof(volume_str), "%.3f", volume); std::system(("pactl set-sink-volume @DEFAULT_SINK@ " + std::string(volume_str)).c_str()); } + + static void config_cpu_rendering() { + setenv("QT_QPA_PLATFORM", "offscreen", 1); + setenv("__GLX_VENDOR_LIBRARY_NAME", "mesa", 1); + } }; diff --git a/system/hardware/tici/hardware.h b/system/hardware/tici/hardware.h index c1a2dcb1694c402..fe0a20ae5807f54 100644 --- a/system/hardware/tici/hardware.h +++ b/system/hardware/tici/hardware.h @@ -103,4 +103,9 @@ class HardwareTici : public HardwareNone { static bool get_ssh_enabled() { return Params().getBool("SshEnabled"); } static void set_ssh_enabled(bool enabled) { Params().putBool("SshEnabled", enabled); } + + static void config_cpu_rendering() { + setenv("QT_QPA_PLATFORM", "eglfs", 1); // offscreen doesn't work with EGL/GLES + setenv("LP_NUM_THREADS", "0", 1); // disable threading so we stay on our assigned CPU + } }; From 08054e98009ca90b1b058a63eebccd8dedf57d48 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 6 Nov 2023 09:18:42 -0800 Subject: [PATCH 094/133] bigger map tile cache (#30228) * bigger map tile cache * start with 2x default * Update selfdrive/ui/qt/maps/map_helpers.cc --- selfdrive/ui/qt/maps/map_helpers.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/ui/qt/maps/map_helpers.cc b/selfdrive/ui/qt/maps/map_helpers.cc index ed843610a836b49..022355e3ce0563f 100644 --- a/selfdrive/ui/qt/maps/map_helpers.cc +++ b/selfdrive/ui/qt/maps/map_helpers.cc @@ -21,6 +21,7 @@ QMapboxGLSettings get_mapbox_settings() { if (!Hardware::PC()) { settings.setCacheDatabasePath(MAPS_CACHE_PATH); + settings.setCacheDatabaseMaximumSize(100 * 1024 * 1024); } settings.setApiBaseUrl(MAPS_HOST); settings.setAccessToken(get_mapbox_token()); From ace14698c42e8a1da084a3f2debce043b569a76b Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Mon, 6 Nov 2023 16:22:58 -0500 Subject: [PATCH 095/133] Subaru: 2019-2020 forester is also rate limited (#30391) * forester rate limited * better comment * better comment --- selfdrive/car/subaru/values.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 618d78ae0557b2b..53104d7d0236497 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -725,5 +725,5 @@ def init_make(self, CP: car.CarParams): HYBRID_CARS = {CAR.CROSSTREK_HYBRID, CAR.FORESTER_HYBRID} # Cars that temporarily fault when steering angle rate is greater than some threshold. -# Appears to be all cars that started production after 2020 -STEER_RATE_LIMITED = GLOBAL_GEN2 | {CAR.IMPREZA_2020} +# Appears to be all torque-based cars produced around 2019 - present +STEER_RATE_LIMITED = GLOBAL_GEN2 | {CAR.IMPREZA_2020, CAR.FORESTER} From b4e1ad5e62ea81f0c8b662bdef6fa826a49150e1 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 7 Nov 2023 05:31:00 +0800 Subject: [PATCH 096/133] ui/wifi.cc: fix QPixmap leaks (#30377) fix QPixmap leaks --- selfdrive/ui/qt/widgets/wifi.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/ui/qt/widgets/wifi.cc b/selfdrive/ui/qt/widgets/wifi.cc index ed5825ab775861b..9c5289a22d8c29e 100644 --- a/selfdrive/ui/qt/widgets/wifi.cc +++ b/selfdrive/ui/qt/widgets/wifi.cc @@ -18,8 +18,8 @@ WiFiPromptWidget::WiFiPromptWidget(QWidget *parent) : QFrame(parent) { title_layout->setSpacing(32); { QLabel *icon = new QLabel; - QPixmap *pixmap = new QPixmap("../assets/offroad/icon_wifi_strength_full.svg"); - icon->setPixmap(pixmap->scaledToWidth(80, Qt::SmoothTransformation)); + QPixmap pixmap("../assets/offroad/icon_wifi_strength_full.svg"); + icon->setPixmap(pixmap.scaledToWidth(80, Qt::SmoothTransformation)); title_layout->addWidget(icon); QLabel *title = new QLabel(tr("Setup Wi-Fi")); @@ -68,8 +68,8 @@ WiFiPromptWidget::WiFiPromptWidget(QWidget *parent) : QFrame(parent) { title_layout->addStretch(); QLabel *icon = new QLabel; - QPixmap *pixmap = new QPixmap("../assets/offroad/icon_wifi_uploading.svg"); - icon->setPixmap(pixmap->scaledToWidth(120, Qt::SmoothTransformation)); + QPixmap pixmap("../assets/offroad/icon_wifi_uploading.svg"); + icon->setPixmap(pixmap.scaledToWidth(120, Qt::SmoothTransformation)); title_layout->addWidget(icon); } uploading_layout->addLayout(title_layout); From d2c3c92fb4c9007ab37d0d8242b646f391732283 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 6 Nov 2023 13:55:23 -0800 Subject: [PATCH 097/133] Revert "ui/wifi.cc: fix QPixmap leaks" (#30394) Revert "ui/wifi.cc: fix QPixmap leaks (#30377)" This reverts commit b4e1ad5e62ea81f0c8b662bdef6fa826a49150e1. --- selfdrive/ui/qt/widgets/wifi.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/ui/qt/widgets/wifi.cc b/selfdrive/ui/qt/widgets/wifi.cc index 9c5289a22d8c29e..ed5825ab775861b 100644 --- a/selfdrive/ui/qt/widgets/wifi.cc +++ b/selfdrive/ui/qt/widgets/wifi.cc @@ -18,8 +18,8 @@ WiFiPromptWidget::WiFiPromptWidget(QWidget *parent) : QFrame(parent) { title_layout->setSpacing(32); { QLabel *icon = new QLabel; - QPixmap pixmap("../assets/offroad/icon_wifi_strength_full.svg"); - icon->setPixmap(pixmap.scaledToWidth(80, Qt::SmoothTransformation)); + QPixmap *pixmap = new QPixmap("../assets/offroad/icon_wifi_strength_full.svg"); + icon->setPixmap(pixmap->scaledToWidth(80, Qt::SmoothTransformation)); title_layout->addWidget(icon); QLabel *title = new QLabel(tr("Setup Wi-Fi")); @@ -68,8 +68,8 @@ WiFiPromptWidget::WiFiPromptWidget(QWidget *parent) : QFrame(parent) { title_layout->addStretch(); QLabel *icon = new QLabel; - QPixmap pixmap("../assets/offroad/icon_wifi_uploading.svg"); - icon->setPixmap(pixmap.scaledToWidth(120, Qt::SmoothTransformation)); + QPixmap *pixmap = new QPixmap("../assets/offroad/icon_wifi_uploading.svg"); + icon->setPixmap(pixmap->scaledToWidth(120, Qt::SmoothTransformation)); title_layout->addWidget(icon); } uploading_layout->addLayout(title_layout); From 9257066c4e52c156cb88de78f0a94006baf877ad Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Mon, 6 Nov 2023 19:36:48 -0500 Subject: [PATCH 098/133] Mapsd: disable threading on PC too (#30396) single threaded rendering --- system/hardware/pc/hardware.h | 1 + 1 file changed, 1 insertion(+) diff --git a/system/hardware/pc/hardware.h b/system/hardware/pc/hardware.h index 63244c5c5db3052..7a7ddd60b7df634 100644 --- a/system/hardware/pc/hardware.h +++ b/system/hardware/pc/hardware.h @@ -24,5 +24,6 @@ class HardwarePC : public HardwareNone { static void config_cpu_rendering() { setenv("QT_QPA_PLATFORM", "offscreen", 1); setenv("__GLX_VENDOR_LIBRARY_NAME", "mesa", 1); + setenv("LP_NUM_THREADS", "0", 1); // disable threading so we stay on our assigned CPU } }; From af86e305669b477d76a14485bd750f843aa0175d Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 6 Nov 2023 21:26:52 -0800 Subject: [PATCH 099/133] remove mapsd exit code exception (#30398) --- selfdrive/manager/test/test_manager.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/selfdrive/manager/test/test_manager.py b/selfdrive/manager/test/test_manager.py index 89ad4837446adb9..d4d4e64f78e95ee 100755 --- a/selfdrive/manager/test/test_manager.py +++ b/selfdrive/manager/test/test_manager.py @@ -66,10 +66,6 @@ def test_clean_exit(self): self.assertNotIn(p.name, BLACKLIST_PROCS, f"{p.name} was started") - # TODO: mapsd should exit cleanly - if p.name == "mapsd": - continue - 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 From 60b21b55d28473046825346845b609a5324d945c Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Tue, 7 Nov 2023 01:13:39 -0500 Subject: [PATCH 100/133] Subaru: initial eyesight disable support (#30373) * initial eyesight disable * disable_eyesight * comment --- selfdrive/car/subaru/carcontroller.py | 18 +++++++++++++++++- selfdrive/car/subaru/interface.py | 11 ++++++++++- selfdrive/car/subaru/subarucan.py | 24 ++++++++++++++++++++++++ selfdrive/car/subaru/values.py | 5 +++++ selfdrive/car/tests/routes.py | 1 + 5 files changed, 57 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index 19304efdb1a07de..c277f012ab7764f 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -2,7 +2,8 @@ from opendbc.can.packer import CANPacker from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance from openpilot.selfdrive.car.subaru import subarucan -from openpilot.selfdrive.car.subaru.values import DBC, GLOBAL_GEN2, PREGLOBAL_CARS, HYBRID_CARS, STEER_RATE_LIMITED, CanBus, CarControllerParams, SubaruFlags +from openpilot.selfdrive.car.subaru.values import DBC, GLOBAL_ES_ADDR, GLOBAL_GEN2, PREGLOBAL_CARS, HYBRID_CARS, STEER_RATE_LIMITED, \ + CanBus, CarControllerParams, SubaruFlags # FIXME: These limits aren't exact. The real limit is more than likely over a larger time period and # involves the total steering angle change rather than rate, but these limits work well for now @@ -119,6 +120,21 @@ def update(self, CC, CS, now_nanos): bus = CanBus.alt if self.CP.carFingerprint in GLOBAL_GEN2 else CanBus.main can_sends.append(subarucan.create_es_distance(self.packer, CS.es_distance_msg["COUNTER"] + 1, CS.es_distance_msg, bus, pcm_cancel_cmd)) + if self.CP.flags & SubaruFlags.DISABLE_EYESIGHT: + # Tester present (keeps eyesight disabled) + if self.frame % 100 == 0: + can_sends.append([GLOBAL_ES_ADDR, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", CanBus.camera]) + + # Create all of the other eyesight messages to keep the rest of the car happy when eyesight is disabled + if self.frame % 5 == 0: + can_sends.append(subarucan.create_es_highbeamassist(self.packer)) + + if self.frame % 10 == 0: + can_sends.append(subarucan.create_es_static_1(self.packer)) + + if self.frame % 2 == 0: + can_sends.append(subarucan.create_es_static_2(self.packer)) + new_actuators = actuators.copy() new_actuators.steer = self.apply_steer_last / self.p.STEER_MAX new_actuators.steerOutputCan = self.apply_steer_last diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index 75bbc8ae91e42db..10ed728812c92a9 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -1,8 +1,9 @@ from cereal import car from panda import Panda from openpilot.selfdrive.car import get_safety_config +from openpilot.selfdrive.car.disable_ecu import disable_ecu from openpilot.selfdrive.car.interfaces import CarInterfaceBase -from openpilot.selfdrive.car.subaru.values import CAR, LKAS_ANGLE, GLOBAL_GEN2, PREGLOBAL_CARS, HYBRID_CARS, SubaruFlags +from openpilot.selfdrive.car.subaru.values import CAR, GLOBAL_ES_ADDR, LKAS_ANGLE, GLOBAL_GEN2, PREGLOBAL_CARS, HYBRID_CARS, SubaruFlags class CarInterface(CarInterfaceBase): @@ -120,6 +121,9 @@ def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): #ret.experimentalLongitudinalAvailable = candidate not in (GLOBAL_GEN2 | PREGLOBAL_CARS | LKAS_ANGLE | HYBRID_CARS) ret.openpilotLongitudinalControl = experimental_long and ret.experimentalLongitudinalAvailable + if candidate in GLOBAL_GEN2 and ret.openpilotLongitudinalControl: + ret.flags |= SubaruFlags.DISABLE_EYESIGHT + if ret.openpilotLongitudinalControl: ret.longitudinalTuning.kpBP = [0., 5., 35.] ret.longitudinalTuning.kpV = [0.8, 1.0, 1.5] @@ -140,5 +144,10 @@ def _update(self, c): return ret + @staticmethod + def init(CP, logcan, sendcan): + if CP.flags & SubaruFlags.DISABLE_EYESIGHT: + disable_ecu(logcan, sendcan, bus=2, addr=GLOBAL_ES_ADDR, com_cont_req=b'\x28\x03\x01') + def apply(self, c, now_nanos): return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/subaru/subarucan.py b/selfdrive/car/subaru/subarucan.py index 57c1ae77410c0ee..7d1939a4974fad9 100644 --- a/selfdrive/car/subaru/subarucan.py +++ b/selfdrive/car/subaru/subarucan.py @@ -243,6 +243,30 @@ def create_es_infotainment(packer, frame, es_infotainment_msg, visual_alert): return packer.make_can_msg("ES_Infotainment", CanBus.main, values) +def create_es_highbeamassist(packer): + values = { + "HBA_Available": False, + } + + return packer.make_can_msg("ES_HighBeamAssist", CanBus.main, values) + + +def create_es_static_1(packer): + values = { + "SET_3": 3, + } + + return packer.make_can_msg("ES_STATIC_1", CanBus.main, values) + + +def create_es_static_2(packer): + values = { + "SET_3": 3, + } + + return packer.make_can_msg("ES_STATIC_2", CanBus.main, values) + + # *** Subaru Pre-global *** def subaru_preglobal_checksum(packer, values, addr, checksum_byte=7): diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 53104d7d0236497..c9dc6ba5db710d5 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -55,6 +55,11 @@ def __init__(self, CP): class SubaruFlags(IntFlag): SEND_INFOTAINMENT = 1 + DISABLE_EYESIGHT = 2 + + +GLOBAL_ES_ADDR = 0x787 +GEN2_ES_BUTTONS_DID = b'\x11\x30' class CanBus: diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index da5d760dfeb02eb..8cf5f3debd75a60 100755 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -251,6 +251,7 @@ class CarTestRoute(NamedTuple): CarTestRoute("791340bc01ed993d|2019-03-10--16-28-08", SUBARU.IMPREZA), CarTestRoute("8bf7e79a3ce64055|2021-05-24--09-36-27", SUBARU.IMPREZA_2020), # CarTestRoute("8de015561e1ea4a0|2023-08-29--17-08-31", SUBARU.IMPREZA), # openpilot longitudinal + # CarTestRoute("c3d1ccb52f5f9d65|2023-07-22--01-23-20", SUBARU.OUTBACK, segment=9), # gen2 longitudinal, eyesight disabled CarTestRoute("1bbe6bf2d62f58a8|2022-07-14--17-11-43", SUBARU.OUTBACK, segment=10), CarTestRoute("c56e69bbc74b8fad|2022-08-18--09-43-51", SUBARU.LEGACY, segment=3), CarTestRoute("f4e3a0c511a076f4|2022-08-04--16-16-48", SUBARU.CROSSTREK_HYBRID, segment=2), From 11855eab5df1409639fb9e94fcf0afa725164b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 7 Nov 2023 11:39:23 -0500 Subject: [PATCH 101/133] power draw test: improve verbosity (#30402) * improve verbosity * unused import --- system/hardware/tici/tests/test_power_draw.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/system/hardware/tici/tests/test_power_draw.py b/system/hardware/tici/tests/test_power_draw.py index 659ed16e22d3ada..64119357499b54d 100755 --- a/system/hardware/tici/tests/test_power_draw.py +++ b/system/hardware/tici/tests/test_power_draw.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 import unittest import time -import math import threading +import numpy as np from dataclasses import dataclass from tabulate import tabulate from typing import List @@ -94,8 +94,8 @@ def test_camera_procs(self): msgs_expected = int(sum(SAMPLE_TIME * SERVICE_LIST[msg].frequency for msg in proc.msgs)) tab.append([proc.name, round(expected, 2), round(cur, 2), msgs_expected, msgs_received]) with self.subTest(proc=proc.name): - self.assertTrue(math.isclose(cur, expected, rel_tol=proc.rtol, abs_tol=proc.atol)) - self.assertTrue(math.isclose(msgs_expected, msgs_received, rel_tol=.02, abs_tol=2)) + np.testing.assert_allclose(cur, expected, rtol=proc.rtol, atol=proc.atol) + np.testing.assert_allclose(msgs_expected, msgs_received, rtol=.02, atol=2) print(tabulate(tab)) print(f"Baseline {baseline:.2f}W\n") From c9fae805bc53e732109fb9e5c36d9674deed0475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 7 Nov 2023 12:54:48 -0500 Subject: [PATCH 102/133] Tinygrad: use compile2 (#30400) * Tinygrad: use compile2 * unused * compile2 file * slightly different * Revert "slightly different" This reverts commit 8a470ecab40c295f3b8c777b82cb7a22890d116e. * slightly different ref * add release file * rm default args --- release/files_common | 4 ++-- selfdrive/modeld/SConscript | 4 ++-- selfdrive/test/process_replay/model_replay_ref_commit | 2 +- tinygrad_repo | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/release/files_common b/release/files_common index 1e16cb9439cf344..9076f440d59d611 100644 --- a/release/files_common +++ b/release/files_common @@ -582,15 +582,15 @@ opendbc/tesla_can.dbc opendbc/tesla_radar.dbc opendbc/tesla_powertrain.dbc -tinygrad_repo/openpilot/compile.py +tinygrad_repo/openpilot/compile2.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/codegen/kernel.py tinygrad_repo/tinygrad/codegen/linearizer.py -tinygrad_repo/tinygrad/codegen/optimizer.py tinygrad_repo/tinygrad/features/image.py +tinygrad_repo/tinygrad/features/search.py tinygrad_repo/tinygrad/nn/* tinygrad_repo/tinygrad/renderer/cstyle.py tinygrad_repo/tinygrad/renderer/opencl.py diff --git a/selfdrive/modeld/SConscript b/selfdrive/modeld/SConscript index 286f3a0a4a18ea5..2d15223d1e0e576 100644 --- a/selfdrive/modeld/SConscript +++ b/selfdrive/modeld/SConscript @@ -58,11 +58,11 @@ lenv.Command(fn + "_metadata.pkl", [fn + ".onnx"]+files, cmd) # Build thneed model if arch == "larch64" or GetOption('pc_thneed'): - tinygrad_opts = ["NOLOCALS=1", "IMAGE=2", "GPU=1"] + tinygrad_opts = [] 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" + cmd = f"cd {Dir('#').abspath}/tinygrad_repo && " + ' '.join(tinygrad_opts) + f" python3 openpilot/compile2.py {fn}.onnx {fn}.thneed" 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) diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index 2785ca71a1e94e4..ddf515181d00473 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -ca18755cd1a1bc28c06e85a280d79d7e48a8438c +d1212a1ac9119a1be33f2e375b1421344379ec08 diff --git a/tinygrad_repo b/tinygrad_repo index 5a4a62ecaecb2bf..ae5d1407ee844a9 160000 --- a/tinygrad_repo +++ b/tinygrad_repo @@ -1 +1 @@ -Subproject commit 5a4a62ecaecb2bfd8bb0f77033aca46df4e668bd +Subproject commit ae5d1407ee844a97a52ad3756835d38e7e2b9e1b From 3c043ba57008ffc053b896d7e7e9a090aaf138ea Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 7 Nov 2023 10:58:01 -0800 Subject: [PATCH 103/133] Update Python packages and pre-commit hooks (#30403) Co-authored-by: adeebshihadeh --- .pre-commit-config.yaml | 6 +- poetry.lock | 737 +++++++++++++++++++--------------------- 2 files changed, 355 insertions(+), 388 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6d99120bd090100..e584758ecbdb5c8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -41,7 +41,7 @@ repos: args: ['--explicit-package-bases'] exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)' - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.3 + rev: v0.1.4 hooks: - id: ruff exclude: '^(third_party/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)' @@ -79,13 +79,13 @@ repos: language: script pass_filenames: false - repo: https://github.com/python-poetry/poetry - rev: '1.6.0' + rev: '1.7.0' hooks: - id: poetry-check name: validate poetry lock args: - --lock - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.27.0 + rev: 0.27.1 hooks: - id: check-github-workflows diff --git a/poetry.lock b/poetry.lock index bfd4491d6b2ef8f..2c91470f54c260c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -554,101 +554,101 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.3.1" +version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.3.1.tar.gz", hash = "sha256:d9137a876020661972ca6eec0766d81aef8a5627df628b664b234b73396e727e"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8aee051c89e13565c6bd366813c386939f8e928af93c29fda4af86d25b73d8f8"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:352a88c3df0d1fa886562384b86f9a9e27563d4704ee0e9d56ec6fcd270ea690"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:223b4d54561c01048f657fa6ce41461d5ad8ff128b9678cfe8b2ecd951e3f8a2"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f861d94c2a450b974b86093c6c027888627b8082f1299dfd5a4bae8e2292821"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1171ef1fc5ab4693c5d151ae0fdad7f7349920eabbaca6271f95969fa0756c2d"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28f512b9a33235545fbbdac6a330a510b63be278a50071a336afc1b78781b147"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0e842112fe3f1a4ffcf64b06dc4c61a88441c2f02f373367f7b4c1aa9be2ad5"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f9bc2ce123637a60ebe819f9fccc614da1bcc05798bbbaf2dd4ec91f3e08846"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f194cce575e59ffe442c10a360182a986535fd90b57f7debfaa5c845c409ecc3"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9a74041ba0bfa9bc9b9bb2cd3238a6ab3b7618e759b41bd15b5f6ad958d17605"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b578cbe580e3b41ad17b1c428f382c814b32a6ce90f2d8e39e2e635d49e498d1"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6db3cfb9b4fcecb4390db154e75b49578c87a3b9979b40cdf90d7e4b945656e1"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:debb633f3f7856f95ad957d9b9c781f8e2c6303ef21724ec94bea2ce2fcbd056"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-win32.whl", hash = "sha256:87071618d3d8ec8b186d53cb6e66955ef2a0e4fa63ccd3709c0c90ac5a43520f"}, - {file = "charset_normalizer-3.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:e372d7dfd154009142631de2d316adad3cc1c36c32a38b16a4751ba78da2a397"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae4070f741f8d809075ef697877fd350ecf0b7c5837ed68738607ee0a2c572cf"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:58e875eb7016fd014c0eea46c6fa92b87b62c0cb31b9feae25cbbe62c919f54d"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dbd95e300367aa0827496fe75a1766d198d34385a58f97683fe6e07f89ca3e3c"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de0b4caa1c8a21394e8ce971997614a17648f94e1cd0640fbd6b4d14cab13a72"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:985c7965f62f6f32bf432e2681173db41336a9c2611693247069288bcb0c7f8b"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a15c1fe6d26e83fd2e5972425a772cca158eae58b05d4a25a4e474c221053e2d"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae55d592b02c4349525b6ed8f74c692509e5adffa842e582c0f861751701a673"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be4d9c2770044a59715eb57c1144dedea7c5d5ae80c68fb9959515037cde2008"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:851cf693fb3aaef71031237cd68699dded198657ec1e76a76eb8be58c03a5d1f"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:31bbaba7218904d2eabecf4feec0d07469284e952a27400f23b6628439439fa7"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:871d045d6ccc181fd863a3cd66ee8e395523ebfbc57f85f91f035f50cee8e3d4"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:501adc5eb6cd5f40a6f77fbd90e5ab915c8fd6e8c614af2db5561e16c600d6f3"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f5fb672c396d826ca16a022ac04c9dce74e00a1c344f6ad1a0fdc1ba1f332213"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-win32.whl", hash = "sha256:bb06098d019766ca16fc915ecaa455c1f1cd594204e7f840cd6258237b5079a8"}, - {file = "charset_normalizer-3.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:8af5a8917b8af42295e86b64903156b4f110a30dca5f3b5aedea123fbd638bff"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7ae8e5142dcc7a49168f4055255dbcced01dc1714a90a21f87448dc8d90617d1"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5b70bab78accbc672f50e878a5b73ca692f45f5b5e25c8066d748c09405e6a55"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ceca5876032362ae73b83347be8b5dbd2d1faf3358deb38c9c88776779b2e2f"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34d95638ff3613849f473afc33f65c401a89f3b9528d0d213c7037c398a51296"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9edbe6a5bf8b56a4a84533ba2b2f489d0046e755c29616ef8830f9e7d9cf5728"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6a02a3c7950cafaadcd46a226ad9e12fc9744652cc69f9e5534f98b47f3bbcf"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10b8dd31e10f32410751b3430996f9807fc4d1587ca69772e2aa940a82ab571a"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edc0202099ea1d82844316604e17d2b175044f9bcb6b398aab781eba957224bd"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b891a2f68e09c5ef989007fac11476ed33c5c9994449a4e2c3386529d703dc8b"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:71ef3b9be10070360f289aea4838c784f8b851be3ba58cf796262b57775c2f14"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:55602981b2dbf8184c098bc10287e8c245e351cd4fdcad050bd7199d5a8bf514"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:46fb9970aa5eeca547d7aa0de5d4b124a288b42eaefac677bde805013c95725c"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:520b7a142d2524f999447b3a0cf95115df81c4f33003c51a6ab637cbda9d0bf4"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-win32.whl", hash = "sha256:8ec8ef42c6cd5856a7613dcd1eaf21e5573b2185263d87d27c8edcae33b62a61"}, - {file = "charset_normalizer-3.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:baec8148d6b8bd5cee1ae138ba658c71f5b03e0d69d5907703e3e1df96db5e41"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63a6f59e2d01310f754c270e4a257426fe5a591dc487f1983b3bbe793cf6bac6"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d6bfc32a68bc0933819cfdfe45f9abc3cae3877e1d90aac7259d57e6e0f85b1"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f3100d86dcd03c03f7e9c3fdb23d92e32abbca07e7c13ebd7ddfbcb06f5991f"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39b70a6f88eebe239fa775190796d55a33cfb6d36b9ffdd37843f7c4c1b5dc67"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e12f8ee80aa35e746230a2af83e81bd6b52daa92a8afaef4fea4a2ce9b9f4fa"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b6cefa579e1237ce198619b76eaa148b71894fb0d6bcf9024460f9bf30fd228"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:61f1e3fb621f5420523abb71f5771a204b33c21d31e7d9d86881b2cffe92c47c"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4f6e2a839f83a6a76854d12dbebde50e4b1afa63e27761549d006fa53e9aa80e"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:1ec937546cad86d0dce5396748bf392bb7b62a9eeb8c66efac60e947697f0e58"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:82ca51ff0fc5b641a2d4e1cc8c5ff108699b7a56d7f3ad6f6da9dbb6f0145b48"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:633968254f8d421e70f91c6ebe71ed0ab140220469cf87a9857e21c16687c034"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-win32.whl", hash = "sha256:c0c72d34e7de5604df0fde3644cc079feee5e55464967d10b24b1de268deceb9"}, - {file = "charset_normalizer-3.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:63accd11149c0f9a99e3bc095bbdb5a464862d77a7e309ad5938fbc8721235ae"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5a3580a4fdc4ac05f9e53c57f965e3594b2f99796231380adb2baaab96e22761"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2465aa50c9299d615d757c1c888bc6fef384b7c4aec81c05a0172b4400f98557"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb7cd68814308aade9d0c93c5bd2ade9f9441666f8ba5aa9c2d4b389cb5e2a45"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91e43805ccafa0a91831f9cd5443aa34528c0c3f2cc48c4cb3d9a7721053874b"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:854cc74367180beb327ab9d00f964f6d91da06450b0855cbbb09187bcdb02de5"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c15070ebf11b8b7fd1bfff7217e9324963c82dbdf6182ff7050519e350e7ad9f"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c4c99f98fc3a1835af8179dcc9013f93594d0670e2fa80c83aa36346ee763d2"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fb765362688821404ad6cf86772fc54993ec11577cd5a92ac44b4c2ba52155b"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dced27917823df984fe0c80a5c4ad75cf58df0fbfae890bc08004cd3888922a2"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a66bcdf19c1a523e41b8e9d53d0cedbfbac2e93c649a2e9502cb26c014d0980c"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ecd26be9f112c4f96718290c10f4caea6cc798459a3a76636b817a0ed7874e42"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3f70fd716855cd3b855316b226a1ac8bdb3caf4f7ea96edcccc6f484217c9597"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:17a866d61259c7de1bdadef418a37755050ddb4b922df8b356503234fff7932c"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-win32.whl", hash = "sha256:548eefad783ed787b38cb6f9a574bd8664468cc76d1538215d510a3cd41406cb"}, - {file = "charset_normalizer-3.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:45f053a0ece92c734d874861ffe6e3cc92150e32136dd59ab1fb070575189c97"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bc791ec3fd0c4309a753f95bb6c749ef0d8ea3aea91f07ee1cf06b7b02118f2f"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0c8c61fb505c7dad1d251c284e712d4e0372cef3b067f7ddf82a7fa82e1e9a93"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2c092be3885a1b7899cd85ce24acedc1034199d6fca1483fa2c3a35c86e43041"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2000c54c395d9e5e44c99dc7c20a64dc371f777faf8bae4919ad3e99ce5253e"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cb50a0335382aac15c31b61d8531bc9bb657cfd848b1d7158009472189f3d62"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c30187840d36d0ba2893bc3271a36a517a717f9fd383a98e2697ee890a37c273"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe81b35c33772e56f4b6cf62cf4aedc1762ef7162a31e6ac7fe5e40d0149eb67"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0bf89afcbcf4d1bb2652f6580e5e55a840fdf87384f6063c4a4f0c95e378656"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:06cf46bdff72f58645434d467bf5228080801298fbba19fe268a01b4534467f5"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3c66df3f41abee950d6638adc7eac4730a306b022570f71dd0bd6ba53503ab57"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd805513198304026bd379d1d516afbf6c3c13f4382134a2c526b8b854da1c2e"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:9505dc359edb6a330efcd2be825fdb73ee3e628d9010597aa1aee5aa63442e97"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:31445f38053476a0c4e6d12b047b08ced81e2c7c712e5a1ad97bc913256f91b2"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-win32.whl", hash = "sha256:bd28b31730f0e982ace8663d108e01199098432a30a4c410d06fe08fdb9e93f4"}, - {file = "charset_normalizer-3.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:555fe186da0068d3354cdf4bbcbc609b0ecae4d04c921cc13e209eece7720727"}, - {file = "charset_normalizer-3.3.1-py3-none-any.whl", hash = "sha256:800561453acdecedaac137bf09cd719c7a440b6800ec182f077bb8e7025fb708"}, + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] [[package]] @@ -740,74 +740,66 @@ cron = ["capturer (>=2.4)"] [[package]] name = "contourpy" -version = "1.1.1" +version = "1.2.0" description = "Python library for calculating contours of 2D quadrilateral grids" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "contourpy-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:46e24f5412c948d81736509377e255f6040e94216bf1a9b5ea1eaa9d29f6ec1b"}, - {file = "contourpy-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e48694d6a9c5a26ee85b10130c77a011a4fedf50a7279fa0bdaf44bafb4299d"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a66045af6cf00e19d02191ab578a50cb93b2028c3eefed999793698e9ea768ae"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ebf42695f75ee1a952f98ce9775c873e4971732a87334b099dde90b6af6a916"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6aec19457617ef468ff091669cca01fa7ea557b12b59a7908b9474bb9674cf0"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:462c59914dc6d81e0b11f37e560b8a7c2dbab6aca4f38be31519d442d6cde1a1"}, - {file = "contourpy-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6d0a8efc258659edc5299f9ef32d8d81de8b53b45d67bf4bfa3067f31366764d"}, - {file = "contourpy-1.1.1-cp310-cp310-win32.whl", hash = "sha256:d6ab42f223e58b7dac1bb0af32194a7b9311065583cc75ff59dcf301afd8a431"}, - {file = "contourpy-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:549174b0713d49871c6dee90a4b499d3f12f5e5f69641cd23c50a4542e2ca1eb"}, - {file = "contourpy-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:407d864db716a067cc696d61fa1ef6637fedf03606e8417fe2aeed20a061e6b2"}, - {file = "contourpy-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe80c017973e6a4c367e037cb31601044dd55e6bfacd57370674867d15a899b"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e30aaf2b8a2bac57eb7e1650df1b3a4130e8d0c66fc2f861039d507a11760e1b"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3de23ca4f381c3770dee6d10ead6fff524d540c0f662e763ad1530bde5112532"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:566f0e41df06dfef2431defcfaa155f0acfa1ca4acbf8fd80895b1e7e2ada40e"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b04c2f0adaf255bf756cf08ebef1be132d3c7a06fe6f9877d55640c5e60c72c5"}, - {file = "contourpy-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d0c188ae66b772d9d61d43c6030500344c13e3f73a00d1dc241da896f379bb62"}, - {file = "contourpy-1.1.1-cp311-cp311-win32.whl", hash = "sha256:0683e1ae20dc038075d92e0e0148f09ffcefab120e57f6b4c9c0f477ec171f33"}, - {file = "contourpy-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:8636cd2fc5da0fb102a2504fa2c4bea3cbc149533b345d72cdf0e7a924decc45"}, - {file = "contourpy-1.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:560f1d68a33e89c62da5da4077ba98137a5e4d3a271b29f2f195d0fba2adcb6a"}, - {file = "contourpy-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:24216552104ae8f3b34120ef84825400b16eb6133af2e27a190fdc13529f023e"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56de98a2fb23025882a18b60c7f0ea2d2d70bbbcfcf878f9067234b1c4818442"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:07d6f11dfaf80a84c97f1a5ba50d129d9303c5b4206f776e94037332e298dda8"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1eaac5257a8f8a047248d60e8f9315c6cff58f7803971170d952555ef6344a7"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19557fa407e70f20bfaba7d55b4d97b14f9480856c4fb65812e8a05fe1c6f9bf"}, - {file = "contourpy-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:081f3c0880712e40effc5f4c3b08feca6d064cb8cfbb372ca548105b86fd6c3d"}, - {file = "contourpy-1.1.1-cp312-cp312-win32.whl", hash = "sha256:059c3d2a94b930f4dafe8105bcdc1b21de99b30b51b5bce74c753686de858cb6"}, - {file = "contourpy-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:f44d78b61740e4e8c71db1cf1fd56d9050a4747681c59ec1094750a658ceb970"}, - {file = "contourpy-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:70e5a10f8093d228bb2b552beeb318b8928b8a94763ef03b858ef3612b29395d"}, - {file = "contourpy-1.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8394e652925a18ef0091115e3cc191fef350ab6dc3cc417f06da66bf98071ae9"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5bd5680f844c3ff0008523a71949a3ff5e4953eb7701b28760805bc9bcff217"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66544f853bfa85c0d07a68f6c648b2ec81dafd30f272565c37ab47a33b220684"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0c02b75acfea5cab07585d25069207e478d12309557f90a61b5a3b4f77f46ce"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41339b24471c58dc1499e56783fedc1afa4bb018bcd035cfb0ee2ad2a7501ef8"}, - {file = "contourpy-1.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f29fb0b3f1217dfe9362ec55440d0743fe868497359f2cf93293f4b2701b8251"}, - {file = "contourpy-1.1.1-cp38-cp38-win32.whl", hash = "sha256:f9dc7f933975367251c1b34da882c4f0e0b2e24bb35dc906d2f598a40b72bfc7"}, - {file = "contourpy-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:498e53573e8b94b1caeb9e62d7c2d053c263ebb6aa259c81050766beb50ff8d9"}, - {file = "contourpy-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ba42e3810999a0ddd0439e6e5dbf6d034055cdc72b7c5c839f37a7c274cb4eba"}, - {file = "contourpy-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c06e4c6e234fcc65435223c7b2a90f286b7f1b2733058bdf1345d218cc59e34"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca6fab080484e419528e98624fb5c4282148b847e3602dc8dbe0cb0669469887"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93df44ab351119d14cd1e6b52a5063d3336f0754b72736cc63db59307dabb718"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eafbef886566dc1047d7b3d4b14db0d5b7deb99638d8e1be4e23a7c7ac59ff0f"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efe0fab26d598e1ec07d72cf03eaeeba8e42b4ecf6b9ccb5a356fde60ff08b85"}, - {file = "contourpy-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f08e469821a5e4751c97fcd34bcb586bc243c39c2e39321822060ba902eac49e"}, - {file = "contourpy-1.1.1-cp39-cp39-win32.whl", hash = "sha256:bfc8a5e9238232a45ebc5cb3bfee71f1167064c8d382cadd6076f0d51cff1da0"}, - {file = "contourpy-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:c84fdf3da00c2827d634de4fcf17e3e067490c4aea82833625c4c8e6cdea0887"}, - {file = "contourpy-1.1.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:229a25f68046c5cf8067d6d6351c8b99e40da11b04d8416bf8d2b1d75922521e"}, - {file = "contourpy-1.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a10dab5ea1bd4401c9483450b5b0ba5416be799bbd50fc7a6cc5e2a15e03e8a3"}, - {file = "contourpy-1.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4f9147051cb8fdb29a51dc2482d792b3b23e50f8f57e3720ca2e3d438b7adf23"}, - {file = "contourpy-1.1.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a75cc163a5f4531a256f2c523bd80db509a49fc23721b36dd1ef2f60ff41c3cb"}, - {file = "contourpy-1.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b53d5769aa1f2d4ea407c65f2d1d08002952fac1d9e9d307aa2e1023554a163"}, - {file = "contourpy-1.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11b836b7dbfb74e049c302bbf74b4b8f6cb9d0b6ca1bf86cfa8ba144aedadd9c"}, - {file = "contourpy-1.1.1.tar.gz", hash = "sha256:96ba37c2e24b7212a77da85004c38e7c4d155d3e72a45eeaf22c1f03f607e8ab"}, + {file = "contourpy-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8"}, + {file = "contourpy-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa"}, + {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9"}, + {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab"}, + {file = "contourpy-1.2.0-cp310-cp310-win32.whl", hash = "sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488"}, + {file = "contourpy-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41"}, + {file = "contourpy-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727"}, + {file = "contourpy-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686"}, + {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286"}, + {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95"}, + {file = "contourpy-1.2.0-cp311-cp311-win32.whl", hash = "sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6"}, + {file = "contourpy-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de"}, + {file = "contourpy-1.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0"}, + {file = "contourpy-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0"}, + {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0"}, + {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431"}, + {file = "contourpy-1.2.0-cp312-cp312-win32.whl", hash = "sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f"}, + {file = "contourpy-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9"}, + {file = "contourpy-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc"}, + {file = "contourpy-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5"}, + {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e"}, + {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808"}, + {file = "contourpy-1.2.0-cp39-cp39-win32.whl", hash = "sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4"}, + {file = "contourpy-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956"}, + {file = "contourpy-1.2.0.tar.gz", hash = "sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a"}, ] [package.dependencies] -numpy = {version = ">=1.16,<2.0", markers = "python_version <= \"3.11\""} +numpy = ">=1.20,<2.0" [package.extras] bokeh = ["bokeh", "selenium"] docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.4.1)", "types-Pillow"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.6.1)", "types-Pillow"] test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] -test-no-images = ["pytest", "pytest-cov", "wurlitzer"] +test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] [[package]] name = "control" @@ -1191,57 +1183,57 @@ files = [ [[package]] name = "fonttools" -version = "4.43.1" +version = "4.44.0" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.43.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bf11e2cca121df35e295bd34b309046c29476ee739753bc6bc9d5050de319273"}, - {file = "fonttools-4.43.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10b3922875ffcba636674f406f9ab9a559564fdbaa253d66222019d569db869c"}, - {file = "fonttools-4.43.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f727c3e3d08fd25352ed76cc3cb61486f8ed3f46109edf39e5a60fc9fecf6ca"}, - {file = "fonttools-4.43.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad0b3f6342cfa14be996971ea2b28b125ad681c6277c4cd0fbdb50340220dfb6"}, - {file = "fonttools-4.43.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3b7ad05b2beeebafb86aa01982e9768d61c2232f16470f9d0d8e385798e37184"}, - {file = "fonttools-4.43.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4c54466f642d2116686268c3e5f35ebb10e49b0d48d41a847f0e171c785f7ac7"}, - {file = "fonttools-4.43.1-cp310-cp310-win32.whl", hash = "sha256:1e09da7e8519e336239fbd375156488a4c4945f11c4c5792ee086dd84f784d02"}, - {file = "fonttools-4.43.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cf9e974f63b1080b1d2686180fc1fbfd3bfcfa3e1128695b5de337eb9075cef"}, - {file = "fonttools-4.43.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5db46659cfe4e321158de74c6f71617e65dc92e54980086823a207f1c1c0e24b"}, - {file = "fonttools-4.43.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1952c89a45caceedf2ab2506d9a95756e12b235c7182a7a0fff4f5e52227204f"}, - {file = "fonttools-4.43.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c36da88422e0270fbc7fd959dc9749d31a958506c1d000e16703c2fce43e3d0"}, - {file = "fonttools-4.43.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bbbf8174501285049e64d174e29f9578495e1b3b16c07c31910d55ad57683d8"}, - {file = "fonttools-4.43.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d4071bd1c183b8d0b368cc9ed3c07a0f6eb1bdfc4941c4c024c49a35429ac7cd"}, - {file = "fonttools-4.43.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d21099b411e2006d3c3e1f9aaf339e12037dbf7bf9337faf0e93ec915991f43b"}, - {file = "fonttools-4.43.1-cp311-cp311-win32.whl", hash = "sha256:b84a1c00f832feb9d0585ca8432fba104c819e42ff685fcce83537e2e7e91204"}, - {file = "fonttools-4.43.1-cp311-cp311-win_amd64.whl", hash = "sha256:9a2f0aa6ca7c9bc1058a9d0b35483d4216e0c1bbe3962bc62ce112749954c7b8"}, - {file = "fonttools-4.43.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4d9740e3783c748521e77d3c397dc0662062c88fd93600a3c2087d3d627cd5e5"}, - {file = "fonttools-4.43.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:884ef38a5a2fd47b0c1291647b15f4e88b9de5338ffa24ee52c77d52b4dfd09c"}, - {file = "fonttools-4.43.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9648518ef687ba818db3fcc5d9aae27a369253ac09a81ed25c3867e8657a0680"}, - {file = "fonttools-4.43.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95e974d70238fc2be5f444fa91f6347191d0e914d5d8ae002c9aa189572cc215"}, - {file = "fonttools-4.43.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:34f713dad41aa21c637b4e04fe507c36b986a40f7179dcc86402237e2d39dcd3"}, - {file = "fonttools-4.43.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:360201d46165fc0753229afe785900bc9596ee6974833124f4e5e9f98d0f592b"}, - {file = "fonttools-4.43.1-cp312-cp312-win32.whl", hash = "sha256:bb6d2f8ef81ea076877d76acfb6f9534a9c5f31dc94ba70ad001267ac3a8e56f"}, - {file = "fonttools-4.43.1-cp312-cp312-win_amd64.whl", hash = "sha256:25d3da8a01442cbc1106490eddb6d31d7dffb38c1edbfabbcc8db371b3386d72"}, - {file = "fonttools-4.43.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8da417431bfc9885a505e86ba706f03f598c85f5a9c54f67d63e84b9948ce590"}, - {file = "fonttools-4.43.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:51669b60ee2a4ad6c7fc17539a43ffffc8ef69fd5dbed186a38a79c0ac1f5db7"}, - {file = "fonttools-4.43.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748015d6f28f704e7d95cd3c808b483c5fb87fd3eefe172a9da54746ad56bfb6"}, - {file = "fonttools-4.43.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7a58eb5e736d7cf198eee94844b81c9573102ae5989ebcaa1d1a37acd04b33d"}, - {file = "fonttools-4.43.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6bb5ea9076e0e39defa2c325fc086593ae582088e91c0746bee7a5a197be3da0"}, - {file = "fonttools-4.43.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5f37e31291bf99a63328668bb83b0669f2688f329c4c0d80643acee6e63cd933"}, - {file = "fonttools-4.43.1-cp38-cp38-win32.whl", hash = "sha256:9c60ecfa62839f7184f741d0509b5c039d391c3aff71dc5bc57b87cc305cff3b"}, - {file = "fonttools-4.43.1-cp38-cp38-win_amd64.whl", hash = "sha256:fe9b1ec799b6086460a7480e0f55c447b1aca0a4eecc53e444f639e967348896"}, - {file = "fonttools-4.43.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13a9a185259ed144def3682f74fdcf6596f2294e56fe62dfd2be736674500dba"}, - {file = "fonttools-4.43.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2adca1b46d69dce4a37eecc096fe01a65d81a2f5c13b25ad54d5430ae430b13"}, - {file = "fonttools-4.43.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18eefac1b247049a3a44bcd6e8c8fd8b97f3cad6f728173b5d81dced12d6c477"}, - {file = "fonttools-4.43.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2062542a7565091cea4cc14dd99feff473268b5b8afdee564f7067dd9fff5860"}, - {file = "fonttools-4.43.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18a2477c62a728f4d6e88c45ee9ee0229405e7267d7d79ce1f5ce0f3e9f8ab86"}, - {file = "fonttools-4.43.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a7a06f8d95b7496e53af80d974d63516ffb263a468e614978f3899a6df52d4b3"}, - {file = "fonttools-4.43.1-cp39-cp39-win32.whl", hash = "sha256:10003ebd81fec0192c889e63a9c8c63f88c7d72ae0460b7ba0cd2a1db246e5ad"}, - {file = "fonttools-4.43.1-cp39-cp39-win_amd64.whl", hash = "sha256:e117a92b07407a061cde48158c03587ab97e74e7d73cb65e6aadb17af191162a"}, - {file = "fonttools-4.43.1-py3-none-any.whl", hash = "sha256:4f88cae635bfe4bbbdc29d479a297bb525a94889184bb69fa9560c2d4834ddb9"}, - {file = "fonttools-4.43.1.tar.gz", hash = "sha256:17dbc2eeafb38d5d0e865dcce16e313c58265a6d2d20081c435f84dc5a9d8212"}, + {file = "fonttools-4.44.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e1cd1c6bb097e774d68402499ff66185190baaa2629ae2f18515a2c50b93db0c"}, + {file = "fonttools-4.44.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9eab7f9837fdaa2a10a524fbcc2ec24bf60637c044b6e4a59c3f835b90f0fae"}, + {file = "fonttools-4.44.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f412954275e594f7a51c16f3b3edd850acb0d842fefc33856b63a17e18499a5"}, + {file = "fonttools-4.44.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50d25893885e80a5955186791eed5579f1e75921751539cc1dc3ffd1160b48cf"}, + {file = "fonttools-4.44.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:22ea8aa7b3712450b42b044702bd3a64fd118006bad09a6f94bd1b227088492e"}, + {file = "fonttools-4.44.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df40daa6c03b98652ffe8110ae014fe695437f6e1cb5a07e16ea37f40e73ac86"}, + {file = "fonttools-4.44.0-cp310-cp310-win32.whl", hash = "sha256:bca49da868e8bde569ef36f0cc1b6de21d56bf9c3be185c503b629c19a185287"}, + {file = "fonttools-4.44.0-cp310-cp310-win_amd64.whl", hash = "sha256:dbac86d83d96099890e731cc2af97976ff2c98f4ba432fccde657c5653a32f1c"}, + {file = "fonttools-4.44.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e8ff7d19a6804bfd561cfcec9b4200dd1788e28f7de4be70189801530c47c1b3"}, + {file = "fonttools-4.44.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8a1fa9a718de0bc026979c93e1e9b55c5efde60d76f91561fd713387573817d"}, + {file = "fonttools-4.44.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05064f95aacdfc06f21e55096c964b2228d942b8675fa26995a2551f6329d2d"}, + {file = "fonttools-4.44.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31b38528f25bc662401e6ffae14b3eb7f1e820892fd80369a37155e3b636a2f4"}, + {file = "fonttools-4.44.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:05d7c4d2c95b9490e669f3cb83918799bf1c838619ac6d3bad9ea017cfc63f2e"}, + {file = "fonttools-4.44.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6999e80a125b0cd8e068d0210b63323f17338038c2ecd2e11b9209ec430fe7f2"}, + {file = "fonttools-4.44.0-cp311-cp311-win32.whl", hash = "sha256:a7aec7f5d14dfcd71fb3ebc299b3f000c21fdc4043079101777ed2042ba5b7c5"}, + {file = "fonttools-4.44.0-cp311-cp311-win_amd64.whl", hash = "sha256:518a945dbfe337744bfff31423c1430303b8813c5275dffb0f2577f0734a1189"}, + {file = "fonttools-4.44.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:59b6ad83cce067d10f4790c037a5904424f45bebb5e7be2eb2db90402f288267"}, + {file = "fonttools-4.44.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c2de1fb18198acd400c45ffe2aef5420c8d55fde903e91cba705596099550f3b"}, + {file = "fonttools-4.44.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84f308b7a8d28208d54315d11d35f9888d6d607673dd4d42d60b463682ee0400"}, + {file = "fonttools-4.44.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66bc6efd829382f7a7e6cf33c2fb32b13edc8a239eb15f32acbf197dce7a0165"}, + {file = "fonttools-4.44.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a8b99713d3a0d0e876b6aecfaada5e7dc9fe979fcd90ef9fa0ba1d9b9aed03f2"}, + {file = "fonttools-4.44.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b63da598d9cbc52e2381f922da0e94d60c0429f92207bd3fb04d112fc82ea7cb"}, + {file = "fonttools-4.44.0-cp312-cp312-win32.whl", hash = "sha256:f611c97678604e302b725f71626edea113a5745a7fb557c958b39edb6add87d5"}, + {file = "fonttools-4.44.0-cp312-cp312-win_amd64.whl", hash = "sha256:58af428746fa73a2edcbf26aff33ac4ef3c11c8d75bb200eaea2f7e888d2de4e"}, + {file = "fonttools-4.44.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9ee8692e23028564c13d924004495f284df8ac016a19f17a87251210e1f1f928"}, + {file = "fonttools-4.44.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dab3d00d27b1a79ae4d4a240e8ceea8af0ff049fd45f05adb4f860d93744110d"}, + {file = "fonttools-4.44.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f53526668beccdb3409c6055a4ffe50987a7f05af6436fa55d61f5e7bd450219"}, + {file = "fonttools-4.44.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3da036b016c975c2d8c69005bdc4d5d16266f948a7fab950244e0f58301996a"}, + {file = "fonttools-4.44.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b99fe8ef4093f672d00841569d2d05691e50334d79f4d9c15c1265d76d5580d2"}, + {file = "fonttools-4.44.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d16d9634ff1e5cea2cf4a8cbda9026f766e4b5f30b48f8180f0e99133d3abfc"}, + {file = "fonttools-4.44.0-cp38-cp38-win32.whl", hash = "sha256:3d29509f6e05e8d725db59c2d8c076223d793e4e35773040be6632a0349f2f97"}, + {file = "fonttools-4.44.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4fa4f4bc8fd86579b8cdbe5e948f35d82c0eda0091c399d009b2a5a6b61c040"}, + {file = "fonttools-4.44.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c794de4086f06ae609b71ac944ec7deb09f34ecf73316fddc041087dd24bba39"}, + {file = "fonttools-4.44.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2db63941fee3122e31a21dd0f5b2138ce9906b661a85b63622421d3654a74ae2"}, + {file = "fonttools-4.44.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb01c49c8aa035d5346f46630209923d4927ed15c2493db38d31da9f811eb70d"}, + {file = "fonttools-4.44.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46c79af80a835410874683b5779b6c1ec1d5a285e11c45b5193e79dd691eb111"}, + {file = "fonttools-4.44.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b6e6aa2d066f8dafd06d8d0799b4944b5d5a1f015dd52ac01bdf2895ebe169a0"}, + {file = "fonttools-4.44.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:63a3112f753baef8c6ac2f5f574bb9ac8001b86c8c0c0380039db47a7f512d20"}, + {file = "fonttools-4.44.0-cp39-cp39-win32.whl", hash = "sha256:54efed22b2799a85475e6840e907c402ba49892c614565dc770aa97a53621b2b"}, + {file = "fonttools-4.44.0-cp39-cp39-win_amd64.whl", hash = "sha256:2e91e19b583961979e2e5a701269d3cfc07418963bee717f8160b0a24332826b"}, + {file = "fonttools-4.44.0-py3-none-any.whl", hash = "sha256:b9beb0fa6ff3ea808ad4a6962d68ac0f140ddab080957b20d9e268e4d67fb335"}, + {file = "fonttools-4.44.0.tar.gz", hash = "sha256:4e90dd81b6e0d97ebfe52c0d12a17a9ef7f305d6bfbb93081265057d6092f252"}, ] [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 (>=15.0.0)", "xattr", "zopfli (>=0.1.4)"] +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 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] graphite = ["lz4 (>=1.7.4.2)"] interpolatable = ["munkres", "scipy"] lxml = ["lxml (>=4.0,<5)"] @@ -1251,7 +1243,7 @@ repacker = ["uharfbuzz (>=0.23.0)"] symfont = ["sympy"] type1 = ["xattr"] ufo = ["fs (>=2.2.0,<3)"] -unicode = ["unicodedata2 (>=15.0.0)"] +unicode = ["unicodedata2 (>=15.1.0)"] woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] @@ -1698,13 +1690,13 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs [[package]] name = "importlib-resources" -version = "6.1.0" +version = "6.1.1" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.0-py3-none-any.whl", hash = "sha256:aa50258bbfa56d4e33fbd8aa3ef48ded10d1735f11532b8df95388cc6bdb7e83"}, - {file = "importlib_resources-6.1.0.tar.gz", hash = "sha256:9d48dcccc213325e810fd723e7fbb45ccb39f6cf5c31f00cf2b965f5f10f3cb9"}, + {file = "importlib_resources-6.1.1-py3-none-any.whl", hash = "sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6"}, + {file = "importlib_resources-6.1.1.tar.gz", hash = "sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a"}, ] [package.extras] @@ -1921,93 +1913,92 @@ files = [ [[package]] name = "lru-dict" -version = "1.2.0" +version = "1.3.0" description = "An Dict like LRU container." optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "lru-dict-1.2.0.tar.gz", hash = "sha256:13c56782f19d68ddf4d8db0170041192859616514c706b126d0df2ec72a11bd7"}, - {file = "lru_dict-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:de906e5486b5c053d15b7731583c25e3c9147c288ac8152a6d1f9bccdec72641"}, - {file = "lru_dict-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:604d07c7604b20b3130405d137cae61579578b0e8377daae4125098feebcb970"}, - {file = "lru_dict-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:203b3e78d03d88f491fa134f85a42919020686b6e6f2d09759b2f5517260c651"}, - {file = "lru_dict-1.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:020b93870f8c7195774cbd94f033b96c14f51c57537969965c3af300331724fe"}, - {file = "lru_dict-1.2.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1184d91cfebd5d1e659d47f17a60185bbf621635ca56dcdc46c6a1745d25df5c"}, - {file = "lru_dict-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fc42882b554a86e564e0b662da47b8a4b32fa966920bd165e27bb8079a323bc1"}, - {file = "lru_dict-1.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:18ee88ada65bd2ffd483023be0fa1c0a6a051ef666d1cd89e921dcce134149f2"}, - {file = "lru_dict-1.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:756230c22257597b7557eaef7f90484c489e9ba78e5bb6ab5a5bcfb6b03cb075"}, - {file = "lru_dict-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c4da599af36618881748b5db457d937955bb2b4800db891647d46767d636c408"}, - {file = "lru_dict-1.2.0-cp310-cp310-win32.whl", hash = "sha256:35a142a7d1a4fd5d5799cc4f8ab2fff50a598d8cee1d1c611f50722b3e27874f"}, - {file = "lru_dict-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:6da5b8099766c4da3bf1ed6e7d7f5eff1681aff6b5987d1258a13bd2ed54f0c9"}, - {file = "lru_dict-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b20b7c9beb481e92e07368ebfaa363ed7ef61e65ffe6e0edbdbaceb33e134124"}, - {file = "lru_dict-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22147367b296be31cc858bf167c448af02435cac44806b228c9be8117f1bfce4"}, - {file = "lru_dict-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34a3091abeb95e707f381a8b5b7dc8e4ee016316c659c49b726857b0d6d1bd7a"}, - {file = "lru_dict-1.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:877801a20f05c467126b55338a4e9fa30e2a141eb7b0b740794571b7d619ee11"}, - {file = "lru_dict-1.2.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d3336e901acec897bcd318c42c2b93d5f1d038e67688f497045fc6bad2c0be7"}, - {file = "lru_dict-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8dafc481d2defb381f19b22cc51837e8a42631e98e34b9e0892245cc96593deb"}, - {file = "lru_dict-1.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:87bbad3f5c3de8897b8c1263a9af73bbb6469fb90e7b57225dad89b8ef62cd8d"}, - {file = "lru_dict-1.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:25f9e0bc2fe8f41c2711ccefd2871f8a5f50a39e6293b68c3dec576112937aad"}, - {file = "lru_dict-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ae301c282a499dc1968dd633cfef8771dd84228ae9d40002a3ea990e4ff0c469"}, - {file = "lru_dict-1.2.0-cp311-cp311-win32.whl", hash = "sha256:c9617583173a29048e11397f165501edc5ae223504a404b2532a212a71ecc9ed"}, - {file = "lru_dict-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6b7a031e47421d4b7aa626b8c91c180a9f037f89e5d0a71c4bb7afcf4036c774"}, - {file = "lru_dict-1.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ea2ac3f7a7a2f32f194c84d82a034e66780057fd908b421becd2f173504d040e"}, - {file = "lru_dict-1.2.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd46c94966f631a81ffe33eee928db58e9fbee15baba5923d284aeadc0e0fa76"}, - {file = "lru_dict-1.2.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:086ce993414f0b28530ded7e004c77dc57c5748fa6da488602aa6e7f79e6210e"}, - {file = "lru_dict-1.2.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df25a426446197488a6702954dcc1de511deee20c9db730499a2aa83fddf0df1"}, - {file = "lru_dict-1.2.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c53b12b89bd7a6c79f0536ff0d0a84fdf4ab5f6252d94b24b9b753bd9ada2ddf"}, - {file = "lru_dict-1.2.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:f9484016e6765bd295708cccc9def49f708ce07ac003808f69efa386633affb9"}, - {file = "lru_dict-1.2.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d0f7ec902a0097ac39f1922c89be9eaccf00eb87751e28915320b4f72912d057"}, - {file = "lru_dict-1.2.0-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:981ef3edc82da38d39eb60eae225b88a538d47b90cce2e5808846fd2cf64384b"}, - {file = "lru_dict-1.2.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e25b2e90a032dc248213af7f3f3e975e1934b204f3b16aeeaeaff27a3b65e128"}, - {file = "lru_dict-1.2.0-cp36-cp36m-win32.whl", hash = "sha256:59f3df78e94e07959f17764e7fa7ca6b54e9296953d2626a112eab08e1beb2db"}, - {file = "lru_dict-1.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:de24b47159e07833aeab517d9cb1c3c5c2d6445cc378b1c2f1d8d15fb4841d63"}, - {file = "lru_dict-1.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d0dd4cd58220351233002f910e35cc01d30337696b55c6578f71318b137770f9"}, - {file = "lru_dict-1.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a87bdc291718bbdf9ea4be12ae7af26cbf0706fa62c2ac332748e3116c5510a7"}, - {file = "lru_dict-1.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05fb8744f91f58479cbe07ed80ada6696ec7df21ea1740891d4107a8dd99a970"}, - {file = "lru_dict-1.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00f6e8a3fc91481b40395316a14c94daa0f0a5de62e7e01a7d589f8d29224052"}, - {file = "lru_dict-1.2.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b172fce0a0ffc0fa6d282c14256d5a68b5db1e64719c2915e69084c4b6bf555"}, - {file = "lru_dict-1.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e707d93bae8f0a14e6df1ae8b0f076532b35f00e691995f33132d806a88e5c18"}, - {file = "lru_dict-1.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b9ec7a4a0d6b8297102aa56758434fb1fca276a82ed7362e37817407185c3abb"}, - {file = "lru_dict-1.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:f404dcc8172da1f28da9b1f0087009578e608a4899b96d244925c4f463201f2a"}, - {file = "lru_dict-1.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1171ad3bff32aa8086778be4a3bdff595cc2692e78685bcce9cb06b96b22dcc2"}, - {file = "lru_dict-1.2.0-cp37-cp37m-win32.whl", hash = "sha256:0c316dfa3897fabaa1fe08aae89352a3b109e5f88b25529bc01e98ac029bf878"}, - {file = "lru_dict-1.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5919dd04446bc1ee8d6ecda2187deeebfff5903538ae71083e069bc678599446"}, - {file = "lru_dict-1.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fbf36c5a220a85187cacc1fcb7dd87070e04b5fc28df7a43f6842f7c8224a388"}, - {file = "lru_dict-1.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:712e71b64da181e1c0a2eaa76cd860265980cd15cb0e0498602b8aa35d5db9f8"}, - {file = "lru_dict-1.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f54908bf91280a9b8fa6a8c8f3c2f65850ce6acae2852bbe292391628ebca42f"}, - {file = "lru_dict-1.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3838e33710935da2ade1dd404a8b936d571e29268a70ff4ca5ba758abb3850df"}, - {file = "lru_dict-1.2.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5d5a5f976b39af73324f2b793862859902ccb9542621856d51a5993064f25e4"}, - {file = "lru_dict-1.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8bda3a9afd241ee0181661decaae25e5336ce513ac268ab57da737eacaa7871f"}, - {file = "lru_dict-1.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:bd2cd1b998ea4c8c1dad829fc4fa88aeed4dee555b5e03c132fc618e6123f168"}, - {file = "lru_dict-1.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:b55753ee23028ba8644fd22e50de7b8f85fa60b562a0fafaad788701d6131ff8"}, - {file = "lru_dict-1.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7e51fa6a203fa91d415f3b2900e5748ec8e06ad75777c98cc3aeb3983ca416d7"}, - {file = "lru_dict-1.2.0-cp38-cp38-win32.whl", hash = "sha256:cd6806313606559e6c7adfa0dbeb30fc5ab625f00958c3d93f84831e7a32b71e"}, - {file = "lru_dict-1.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:5d90a70c53b0566084447c3ef9374cc5a9be886e867b36f89495f211baabd322"}, - {file = "lru_dict-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a3ea7571b6bf2090a85ff037e6593bbafe1a8598d5c3b4560eb56187bcccb4dc"}, - {file = "lru_dict-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:287c2115a59c1c9ed0d5d8ae7671e594b1206c36ea9df2fca6b17b86c468ff99"}, - {file = "lru_dict-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5ccfd2291c93746a286c87c3f895165b697399969d24c54804ec3ec559d4e43"}, - {file = "lru_dict-1.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b710f0f4d7ec4f9fa89dfde7002f80bcd77de8024017e70706b0911ea086e2ef"}, - {file = "lru_dict-1.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5345bf50e127bd2767e9fd42393635bbc0146eac01f6baf6ef12c332d1a6a329"}, - {file = "lru_dict-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:291d13f85224551913a78fe695cde04cbca9dcb1d84c540167c443eb913603c9"}, - {file = "lru_dict-1.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d5bb41bc74b321789803d45b124fc2145c1b3353b4ad43296d9d1d242574969b"}, - {file = "lru_dict-1.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0facf49b053bf4926d92d8d5a46fe07eecd2af0441add0182c7432d53d6da667"}, - {file = "lru_dict-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:987b73a06bcf5a95d7dc296241c6b1f9bc6cda42586948c9dabf386dc2bef1cd"}, - {file = "lru_dict-1.2.0-cp39-cp39-win32.whl", hash = "sha256:231d7608f029dda42f9610e5723614a35b1fff035a8060cf7d2be19f1711ace8"}, - {file = "lru_dict-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:71da89e134747e20ed5b8ad5b4ee93fc5b31022c2b71e8176e73c5a44699061b"}, - {file = "lru_dict-1.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:21b3090928c7b6cec509e755cc3ab742154b33660a9b433923bd12c37c448e3e"}, - {file = "lru_dict-1.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaecd7085212d0aa4cd855f38b9d61803d6509731138bf798a9594745953245b"}, - {file = "lru_dict-1.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ead83ac59a29d6439ddff46e205ce32f8b7f71a6bd8062347f77e232825e3d0a"}, - {file = "lru_dict-1.2.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:312b6b2a30188586fe71358f0f33e4bac882d33f5e5019b26f084363f42f986f"}, - {file = "lru_dict-1.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:b30122e098c80e36d0117810d46459a46313421ce3298709170b687dc1240b02"}, - {file = "lru_dict-1.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f010cfad3ab10676e44dc72a813c968cd586f37b466d27cde73d1f7f1ba158c2"}, - {file = "lru_dict-1.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20f5f411f7751ad9a2c02e80287cedf69ae032edd321fe696e310d32dd30a1f8"}, - {file = "lru_dict-1.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:afdadd73304c9befaed02eb42f5f09fdc16288de0a08b32b8080f0f0f6350aa6"}, - {file = "lru_dict-1.2.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7ab0c10c4fa99dc9e26b04e6b62ac32d2bcaea3aad9b81ec8ce9a7aa32b7b1b"}, - {file = "lru_dict-1.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:edad398d5d402c43d2adada390dd83c74e46e020945ff4df801166047013617e"}, - {file = "lru_dict-1.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:91d577a11b84387013815b1ad0bb6e604558d646003b44c92b3ddf886ad0f879"}, - {file = "lru_dict-1.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb12f19cdf9c4f2d9aa259562e19b188ff34afab28dd9509ff32a3f1c2c29326"}, - {file = "lru_dict-1.2.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e4c85aa8844bdca3c8abac3b7f78da1531c74e9f8b3e4890c6e6d86a5a3f6c0"}, - {file = "lru_dict-1.2.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c6acbd097b15bead4de8e83e8a1030bb4d8257723669097eac643a301a952f0"}, - {file = "lru_dict-1.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b6613daa851745dd22b860651de930275be9d3e9373283a2164992abacb75b62"}, + {file = "lru-dict-1.3.0.tar.gz", hash = "sha256:54fd1966d6bd1fcde781596cb86068214edeebff1db13a2cea11079e3fd07b6b"}, + {file = "lru_dict-1.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4073333894db9840f066226d50e6f914a2240711c87d60885d8c940b69a6673f"}, + {file = "lru_dict-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0ad6361e4dd63b47b2fc8eab344198f37387e1da3dcfacfee19bafac3ec9f1eb"}, + {file = "lru_dict-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c637ab54b8cd9802fe19b260261e38820d748adf7606e34045d3c799b6dde813"}, + {file = "lru_dict-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fce5f95489ca1fc158cc9fe0f4866db9cec82c2be0470926a9080570392beaf"}, + {file = "lru_dict-1.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2bf2e24cf5f19c3ff69bf639306e83dced273e6fa775b04e190d7f5cd16f794"}, + {file = "lru_dict-1.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e90059f7701bef3c4da073d6e0434a9c7dc551d5adce30e6b99ef86b186f4b4a"}, + {file = "lru_dict-1.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ecb7ae557239c64077e9b26a142eb88e63cddb104111a5122de7bebbbd00098"}, + {file = "lru_dict-1.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6af36166d22dba851e06a13e35bbf33845d3dd88872e6aebbc8e3e7db70f4682"}, + {file = "lru_dict-1.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ee38d420c77eed548df47b7d74b5169a98e71c9e975596e31ab808e76d11f09"}, + {file = "lru_dict-1.3.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0e1845024c31e6ff246c9eb5e6f6f1a8bb564c06f8a7d6d031220044c081090b"}, + {file = "lru_dict-1.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3ca5474b1649555d014be1104e5558a92497509021a5ba5ea6e9b492303eb66b"}, + {file = "lru_dict-1.3.0-cp310-cp310-win32.whl", hash = "sha256:ebb03a9bd50c2ed86d4f72a54e0aae156d35a14075485b2127c4b01a3f4a63fa"}, + {file = "lru_dict-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:04cda617f4e4c27009005d0a8185ef02829b14b776d2791f5c994cc9d668bc24"}, + {file = "lru_dict-1.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:20c595764695d20bdc3ab9b582e0cc99814da183544afb83783a36d6741a0dac"}, + {file = "lru_dict-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d9b30a8f50c3fa72a494eca6be5810a1b5c89e4f0fda89374f0d1c5ad8d37d51"}, + {file = "lru_dict-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9710737584650a4251b9a566cbb1a86f83437adb209c9ba43a4e756d12faf0d7"}, + {file = "lru_dict-1.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b84c321ae34f2f40aae80e18b6fa08b31c90095792ab64bb99d2e385143effaa"}, + {file = "lru_dict-1.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eed24272b4121b7c22f234daed99899817d81d671b3ed030c876ac88bc9dc890"}, + {file = "lru_dict-1.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd13af06dab7c6ee92284fd02ed9a5613a07d5c1b41948dc8886e7207f86dfd"}, + {file = "lru_dict-1.3.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1efc59bfba6aac33684d87b9e02813b0e2445b2f1c444dae2a0b396ad0ed60c"}, + {file = "lru_dict-1.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cfaf75ac574447afcf8ad998789071af11d2bcf6f947643231f692948839bd98"}, + {file = "lru_dict-1.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c95f8751e2abd6f778da0399c8e0239321d560dbc58cb063827123137d213242"}, + {file = "lru_dict-1.3.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:abd0c284b26b5c4ee806ca4f33ab5e16b4bf4d5ec9e093e75a6f6287acdde78e"}, + {file = "lru_dict-1.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2a47740652b25900ac5ce52667b2eade28d8b5fdca0ccd3323459df710e8210a"}, + {file = "lru_dict-1.3.0-cp311-cp311-win32.whl", hash = "sha256:a690c23fc353681ed8042d9fe8f48f0fb79a57b9a45daea2f0be1eef8a1a4aa4"}, + {file = "lru_dict-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:efd3f4e0385d18f20f7ea6b08af2574c1bfaa5cb590102ef1bee781bdfba84bc"}, + {file = "lru_dict-1.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c279068f68af3b46a5d649855e1fb87f5705fe1f744a529d82b2885c0e1fc69d"}, + {file = "lru_dict-1.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:350e2233cfee9f326a0d7a08e309372d87186565e43a691b120006285a0ac549"}, + {file = "lru_dict-1.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4eafb188a84483b3231259bf19030859f070321b00326dcb8e8c6cbf7db4b12f"}, + {file = "lru_dict-1.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73593791047e36b37fdc0b67b76aeed439fcea80959c7d46201240f9ec3b2563"}, + {file = "lru_dict-1.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1958cb70b9542773d6241974646e5410e41ef32e5c9e437d44040d59bd80daf2"}, + {file = "lru_dict-1.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc1cd3ed2cee78a47f11f3b70be053903bda197a873fd146e25c60c8e5a32cd6"}, + {file = "lru_dict-1.3.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82eb230d48eaebd6977a92ddaa6d788f14cf4f4bcf5bbffa4ddfd60d051aa9d4"}, + {file = "lru_dict-1.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5ad659cbc349d0c9ba8e536b5f40f96a70c360f43323c29f4257f340d891531c"}, + {file = "lru_dict-1.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ba490b8972531d153ac0d4e421f60d793d71a2f4adbe2f7740b3c55dce0a12f1"}, + {file = "lru_dict-1.3.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:c0131351b8a7226c69f1eba5814cbc9d1d8daaf0fdec1ae3f30508e3de5262d4"}, + {file = "lru_dict-1.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0e88dba16695f17f41701269fa046197a3fd7b34a8dba744c8749303ddaa18df"}, + {file = "lru_dict-1.3.0-cp312-cp312-win32.whl", hash = "sha256:6ffaf595e625b388babc8e7d79b40f26c7485f61f16efe76764e32dce9ea17fc"}, + {file = "lru_dict-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf9da32ef2582434842ab6ba6e67290debfae72771255a8e8ab16f3e006de0aa"}, + {file = "lru_dict-1.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c265f16c936a8ff3bb4b8a4bda0be94c15ec28b63e99fdb1439c1ffe4cd437db"}, + {file = "lru_dict-1.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:784ca9d3b0730b3ec199c0a58f66264c63dd5d438119c739c349a6a9be8e5f6e"}, + {file = "lru_dict-1.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e13b2f58f647178470adaa14603bb64cc02eeed32601772ccea30e198252883c"}, + {file = "lru_dict-1.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ffbce5c2e80f57937679553c8f27e61ec327c962bf7ea0b15f1d74277fd5363"}, + {file = "lru_dict-1.3.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7969cb034b3ccc707aff877c73c225c32d7e2a7981baa8f92f5dd4d468fe8c33"}, + {file = "lru_dict-1.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca9ab676609cce85dd65d91c275e47da676d13d77faa72de286fbea30fbaa596"}, + {file = "lru_dict-1.3.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f27c078b5d75989952acbf9b77e14c3dadc468a4aafe85174d548afbc5efc38b"}, + {file = "lru_dict-1.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6123aefe97762ad74215d05320a7f389f196f0594c8813534284d4eafeca1a96"}, + {file = "lru_dict-1.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cd869cadba9a63e1e7fe2dced4a5747d735135b86016b0a63e8c9e324ab629ac"}, + {file = "lru_dict-1.3.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:40a8daddc29c7edb09dfe44292cf111f1e93a8344349778721d430d336b50505"}, + {file = "lru_dict-1.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a03170e4152836987a88dcebde61aaeb73ab7099a00bb86509d45b3fe424230"}, + {file = "lru_dict-1.3.0-cp38-cp38-win32.whl", hash = "sha256:3b4f121afe10f5a82b8e317626eb1e1c325b3f104af56c9756064cd833b1950b"}, + {file = "lru_dict-1.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:1470f5828c7410e16c24b5150eb649647986e78924816e6fb0264049dea14a2b"}, + {file = "lru_dict-1.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a3c9f746a9917e784fffcedeac4c8c47a3dbd90cbe13b69e9140182ad97ce4b7"}, + {file = "lru_dict-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2789296819525a1f3204072dfcf3df6db8bcf69a8fc740ffd3de43a684ea7002"}, + {file = "lru_dict-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:170b66d29945391460351588a7bd8210a95407ae82efe0b855e945398a1d24ea"}, + {file = "lru_dict-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:774ca88501a9effe8797c3db5a6685cf20978c9cb0fe836b6813cfe1ca60d8c9"}, + {file = "lru_dict-1.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:df2e119c6ae412d2fd641a55f8a1e2e51f45a3de3449c18b1b86c319ab79e0c4"}, + {file = "lru_dict-1.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28aa1ea42a7e48174bf513dc2416fea7511a547961e678dc6f5670ca987c18cb"}, + {file = "lru_dict-1.3.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9537e1cee6fa582cb68f2fb9ce82d51faf2ccc0a638b275d033fdcb1478eb80b"}, + {file = "lru_dict-1.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:64545fca797fe2c68c5168efb5f976c6e1459e058cab02445207a079180a3557"}, + {file = "lru_dict-1.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a193a14c66cfc0c259d05dddc5e566a4b09e8f1765e941503d065008feebea9d"}, + {file = "lru_dict-1.3.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:3cb1de0ce4137b060abaafed8474cc0ebd12cedd88aaa7f7b3ebb1ddfba86ae0"}, + {file = "lru_dict-1.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8551ccab1349d4bebedab333dfc8693c74ff728f4b565fe15a6bf7d296bd7ea9"}, + {file = "lru_dict-1.3.0-cp39-cp39-win32.whl", hash = "sha256:6cb0be5e79c3f34d69b90d8559f0221e374b974b809a22377122c4b1a610ff67"}, + {file = "lru_dict-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9f725f2a0bdf1c18735372d5807af4ea3b77888208590394d4660e3d07971f21"}, + {file = "lru_dict-1.3.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f8f7824db5a64581180ab9d09842e6dd9fcdc46aac9cb592a0807cd37ea55680"}, + {file = "lru_dict-1.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acd04b7e7b0c0c192d738df9c317093335e7282c64c9d1bb6b7ebb54674b4e24"}, + {file = "lru_dict-1.3.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5c20f236f27551e3f0adbf1a987673fb1e9c38d6d284502cd38f5a3845ef681"}, + {file = "lru_dict-1.3.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca3703ff03b03a1848c563bc2663d0ad813c1cd42c4d9cf75b623716d4415d9a"}, + {file = "lru_dict-1.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a9fb71ba262c6058a0017ce83d343370d0a0dbe2ae62c2eef38241ec13219330"}, + {file = "lru_dict-1.3.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f5b88a7c39e307739a3701194993455968fcffe437d1facab93546b1b8a334c1"}, + {file = "lru_dict-1.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2682bfca24656fb7a643621520d57b7fe684ed5fa7be008704c1235d38e16a32"}, + {file = "lru_dict-1.3.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96fc87ddf569181827458ec5ad8fa446c4690cffacda66667de780f9fcefd44d"}, + {file = "lru_dict-1.3.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcec98e2c7da7631f0811730303abc4bdfe70d013f7a11e174a2ccd5612a7c59"}, + {file = "lru_dict-1.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:6bba2863060caeaedd8386b0c8ee9a7ce4d57a7cb80ceeddf440b4eff2d013ba"}, + {file = "lru_dict-1.3.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3c497fb60279f1e1d7dfbe150b1b069eaa43f7e172dab03f206282f4994676c5"}, + {file = "lru_dict-1.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d9509d817a47597988615c1a322580c10100acad10c98dfcf3abb41e0e5877f"}, + {file = "lru_dict-1.3.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0213ab4e3d9a8d386c18e485ad7b14b615cb6f05df6ef44fb2a0746c6ea9278b"}, + {file = "lru_dict-1.3.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b50fbd69cd3287196796ab4d50e4cc741eb5b5a01f89d8e930df08da3010c385"}, + {file = "lru_dict-1.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5247d1f011f92666010942434020ddc5a60951fefd5d12a594f0e5d9f43e3b3b"}, ] [package.extras] @@ -2215,52 +2206,51 @@ files = [ [[package]] name = "matplotlib" -version = "3.8.0" +version = "3.8.1" description = "Python plotting package" optional = false python-versions = ">=3.9" files = [ - {file = "matplotlib-3.8.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c4940bad88a932ddc69734274f6fb047207e008389489f2b6f77d9ca485f0e7a"}, - {file = "matplotlib-3.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a33bd3045c7452ca1fa65676d88ba940867880e13e2546abb143035fa9072a9d"}, - {file = "matplotlib-3.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ea6886e93401c22e534bbfd39201ce8931b75502895cfb115cbdbbe2d31f287"}, - {file = "matplotlib-3.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d670b9348e712ec176de225d425f150dc8e37b13010d85233c539b547da0be39"}, - {file = "matplotlib-3.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7b37b74f00c4cb6af908cb9a00779d97d294e89fd2145ad43f0cdc23f635760c"}, - {file = "matplotlib-3.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:0e723f5b96f3cd4aad99103dc93e9e3cdc4f18afdcc76951f4857b46f8e39d2d"}, - {file = "matplotlib-3.8.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5dc945a9cb2deb7d197ba23eb4c210e591d52d77bf0ba27c35fc82dec9fa78d4"}, - {file = "matplotlib-3.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8b5a1bf27d078453aa7b5b27f52580e16360d02df6d3dc9504f3d2ce11f6309"}, - {file = "matplotlib-3.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f25ffb6ad972cdffa7df8e5be4b1e3cadd2f8d43fc72085feb1518006178394"}, - {file = "matplotlib-3.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eee482731c8c17d86d9ddb5194d38621f9b0f0d53c99006275a12523ab021732"}, - {file = "matplotlib-3.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:36eafe2128772195b373e1242df28d1b7ec6c04c15b090b8d9e335d55a323900"}, - {file = "matplotlib-3.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:061ee58facb3580cd2d046a6d227fb77e9295599c5ec6ad069f06b5821ad1cfc"}, - {file = "matplotlib-3.8.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3cc3776836d0f4f22654a7f2d2ec2004618d5cf86b7185318381f73b80fd8a2d"}, - {file = "matplotlib-3.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6c49a2bd6981264bddcb8c317b6bd25febcece9e2ebfcbc34e7f4c0c867c09dc"}, - {file = "matplotlib-3.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23ed11654fc83cd6cfdf6170b453e437674a050a452133a064d47f2f1371f8d3"}, - {file = "matplotlib-3.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dae97fdd6996b3a25da8ee43e3fc734fff502f396801063c6b76c20b56683196"}, - {file = "matplotlib-3.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:87df75f528020a6299f76a1d986c0ed4406e3b2bd44bc5e306e46bca7d45e53e"}, - {file = "matplotlib-3.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:90d74a95fe055f73a6cd737beecc1b81c26f2893b7a3751d52b53ff06ca53f36"}, - {file = "matplotlib-3.8.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c3499c312f5def8f362a2bf761d04fa2d452b333f3a9a3f58805273719bf20d9"}, - {file = "matplotlib-3.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31e793c8bd4ea268cc5d3a695c27b30650ec35238626961d73085d5e94b6ab68"}, - {file = "matplotlib-3.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d5ee602ef517a89d1f2c508ca189cfc395dd0b4a08284fb1b97a78eec354644"}, - {file = "matplotlib-3.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5de39dc61ca35342cf409e031f70f18219f2c48380d3886c1cf5ad9f17898e06"}, - {file = "matplotlib-3.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:dd386c80a98b5f51571b9484bf6c6976de383cd2a8cd972b6a9562d85c6d2087"}, - {file = "matplotlib-3.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:f691b4ef47c7384d0936b2e8ebdeb5d526c81d004ad9403dfb9d4c76b9979a93"}, - {file = "matplotlib-3.8.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0b11f354aae62a2aa53ec5bb09946f5f06fc41793e351a04ff60223ea9162955"}, - {file = "matplotlib-3.8.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f54b9fb87ca5acbcdd0f286021bedc162e1425fa5555ebf3b3dfc167b955ad9"}, - {file = "matplotlib-3.8.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:60a6e04dfd77c0d3bcfee61c3cd335fff1b917c2f303b32524cd1235e194ef99"}, - {file = "matplotlib-3.8.0.tar.gz", hash = "sha256:df8505e1c19d5c2c26aff3497a7cbd3ccfc2e97043d1e4db3e76afa399164b69"}, + {file = "matplotlib-3.8.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e11ab864323fa73ac1b7849688d9671c47a2665242e899785b4db1a375b547e1"}, + {file = "matplotlib-3.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:43a9d40feb63c9e31a0b8b069dcbd74a912f59bdc0095d187126694cd26977e4"}, + {file = "matplotlib-3.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:608ea2951838d391e45dec2e644888db6899c752d3c29e157af9dcefb3d7d8d5"}, + {file = "matplotlib-3.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82ec95b02e894561c21e066bd0c716e4b410df141ce9441aa5af6cd937e4ade2"}, + {file = "matplotlib-3.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e3ad1759ad4a5245172c6d32b8ada603a6020d03211524c39d78d25c9a7dc0d2"}, + {file = "matplotlib-3.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:20a0fdfd3ee836179047f3782be060057b878ad37f5abe29edf006a1ff3ecd73"}, + {file = "matplotlib-3.8.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:7658b7073c1d6a2922ecc0ed41602410fae88586cb8a54f7a2063d537b6beaf7"}, + {file = "matplotlib-3.8.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf6889643d4560fcc56f9f0941f078e4df0d72a6c3e4ca548841fc13c5642664"}, + {file = "matplotlib-3.8.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff842e27bc6a80de08c40e0bfdce460bd08080e8a94af131162b6a1b8948f2cc"}, + {file = "matplotlib-3.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f99d07c0e753717775be7be39ab383453b4d8b629c9fa174596b970c6555890"}, + {file = "matplotlib-3.8.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f34b46dbb1db1f09bfa937cd5853e5f2af232caeeff509c3ab6e43fd33780eae"}, + {file = "matplotlib-3.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1fcb49b6baf0375281979cbf26695ec10bd1cada1e311893e89533b3b70143e7"}, + {file = "matplotlib-3.8.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e17674ee127f78f26fea237e7f4d5cf910a8be82beb6260fedf358b88075b823"}, + {file = "matplotlib-3.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d921c0270647ab11c3ef283efaaa3d46fd005ba233bfb3aea75231cdf3656de8"}, + {file = "matplotlib-3.8.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2afe7d2f8c9e35e94fbcfcfd9b28f29cb32f0a9068cba469cf907428379c8db9"}, + {file = "matplotlib-3.8.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5a504ff40f81d6233603475a45497a6dca37a873393fa20ae6f7dd6596ef72b"}, + {file = "matplotlib-3.8.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cd54bbf089953140905768ed4626d7223e1ad1d7e2a138410a9c4d3b865ccd80"}, + {file = "matplotlib-3.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:27502d2452208ae784c19504644f09f83742809143bbeae147617640930aa344"}, + {file = "matplotlib-3.8.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:f55fb5ff02d999a100be28bf6ffe826e1867a54c7b465409685332c9dd48ffa5"}, + {file = "matplotlib-3.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:afb72822ae410d62aa1a2920c6563cb5680de9078358f0e9474396c6c3e06be2"}, + {file = "matplotlib-3.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43cf368a4a1d8cbc426944806e5e183cead746647a64d2cdb786441546235967"}, + {file = "matplotlib-3.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c54c55457c7f5ea4dfdba0020004fc7667f5c10c8d9b8010d735345acc06c9b8"}, + {file = "matplotlib-3.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e3bb809b743653b5aab5d72ee45c8c937c28e147b0846b0826a54bece898608c"}, + {file = "matplotlib-3.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:c1b0ecaa0d1f4fe1e30f625a2347f0034a89a7d17c39efbb502e554d92ee2f61"}, + {file = "matplotlib-3.8.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ca84deaa38cb64b7dd160ca2046b45f7b5dbff2b0179642e1339fadc337446c9"}, + {file = "matplotlib-3.8.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed3b29f54f6bbf3eaca4cbd23bc260155153ace63b7f597c474fa6fc6f386530"}, + {file = "matplotlib-3.8.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d24c47a1bb47e392fbcd26fe322e4ff3431653ac1e8718e4e147d450ae97a44"}, + {file = "matplotlib-3.8.1.tar.gz", hash = "sha256:044df81c1f6f3a8e52d70c4cfcb44e77ea9632a10929932870dfaa90de94365d"}, ] [package.dependencies] contourpy = ">=1.0.1" cycler = ">=0.10" fonttools = ">=4.22.0" -kiwisolver = ">=1.0.1" +kiwisolver = ">=1.3.1" numpy = ">=1.21,<2" packaging = ">=20.0" -pillow = ">=6.2.0" +pillow = ">=8" pyparsing = ">=2.3.1" python-dateutil = ">=2.7" -setuptools_scm = ">=7" [[package]] name = "mdit-py-plugins" @@ -2371,13 +2361,13 @@ tests = ["pytest (>=4.6)"] [[package]] name = "msal" -version = "1.24.1" +version = "1.25.0" description = "The Microsoft Authentication Library (MSAL) for Python library" optional = false python-versions = ">=2.7" files = [ - {file = "msal-1.24.1-py2.py3-none-any.whl", hash = "sha256:ce4320688f95c301ee74a4d0e9dbcfe029a63663a8cc61756f40d0d0d36574ad"}, - {file = "msal-1.24.1.tar.gz", hash = "sha256:aa0972884b3c6fdec53d9a0bd15c12e5bd7b71ac1b66d746f54d128709f3f8f8"}, + {file = "msal-1.25.0-py2.py3-none-any.whl", hash = "sha256:386df621becb506bc315a713ec3d4d5b5d6163116955c7dde23622f156b81af6"}, + {file = "msal-1.25.0.tar.gz", hash = "sha256:f44329fdb59f4f044c779164a34474b8a44ad9e4940afbc4c3a3a2bbe90324d9"}, ] [package.dependencies] @@ -3243,24 +3233,22 @@ files = [ [[package]] name = "protobuf" -version = "4.24.4" +version = "4.25.0" description = "" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "protobuf-4.24.4-cp310-abi3-win32.whl", hash = "sha256:ec9912d5cb6714a5710e28e592ee1093d68c5ebfeda61983b3f40331da0b1ebb"}, - {file = "protobuf-4.24.4-cp310-abi3-win_amd64.whl", hash = "sha256:1badab72aa8a3a2b812eacfede5020472e16c6b2212d737cefd685884c191085"}, - {file = "protobuf-4.24.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8e61a27f362369c2f33248a0ff6896c20dcd47b5d48239cb9720134bef6082e4"}, - {file = "protobuf-4.24.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:bffa46ad9612e6779d0e51ae586fde768339b791a50610d85eb162daeb23661e"}, - {file = "protobuf-4.24.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:b493cb590960ff863743b9ff1452c413c2ee12b782f48beca77c8da3e2ffe9d9"}, - {file = "protobuf-4.24.4-cp37-cp37m-win32.whl", hash = "sha256:dbbed8a56e56cee8d9d522ce844a1379a72a70f453bde6243e3c86c30c2a3d46"}, - {file = "protobuf-4.24.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6b7d2e1c753715dcfe9d284a25a52d67818dd43c4932574307daf836f0071e37"}, - {file = "protobuf-4.24.4-cp38-cp38-win32.whl", hash = "sha256:02212557a76cd99574775a81fefeba8738d0f668d6abd0c6b1d3adcc75503dbe"}, - {file = "protobuf-4.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:2fa3886dfaae6b4c5ed2730d3bf47c7a38a72b3a1f0acb4d4caf68e6874b947b"}, - {file = "protobuf-4.24.4-cp39-cp39-win32.whl", hash = "sha256:b77272f3e28bb416e2071186cb39efd4abbf696d682cbb5dc731308ad37fa6dd"}, - {file = "protobuf-4.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:9fee5e8aa20ef1b84123bb9232b3f4a5114d9897ed89b4b8142d81924e05d79b"}, - {file = "protobuf-4.24.4-py3-none-any.whl", hash = "sha256:80797ce7424f8c8d2f2547e2d42bfbb6c08230ce5832d6c099a37335c9c90a92"}, - {file = "protobuf-4.24.4.tar.gz", hash = "sha256:5a70731910cd9104762161719c3d883c960151eea077134458503723b60e3667"}, + {file = "protobuf-4.25.0-cp310-abi3-win32.whl", hash = "sha256:5c1203ac9f50e4853b0a0bfffd32c67118ef552a33942982eeab543f5c634395"}, + {file = "protobuf-4.25.0-cp310-abi3-win_amd64.whl", hash = "sha256:c40ff8f00aa737938c5378d461637d15c442a12275a81019cc2fef06d81c9419"}, + {file = "protobuf-4.25.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:cf21faba64cd2c9a3ed92b7a67f226296b10159dbb8fbc5e854fc90657d908e4"}, + {file = "protobuf-4.25.0-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:32ac2100b0e23412413d948c03060184d34a7c50b3e5d7524ee96ac2b10acf51"}, + {file = "protobuf-4.25.0-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:683dc44c61f2620b32ce4927de2108f3ebe8ccf2fd716e1e684e5a50da154054"}, + {file = "protobuf-4.25.0-cp38-cp38-win32.whl", hash = "sha256:1a3ba712877e6d37013cdc3476040ea1e313a6c2e1580836a94f76b3c176d575"}, + {file = "protobuf-4.25.0-cp38-cp38-win_amd64.whl", hash = "sha256:b2cf8b5d381f9378afe84618288b239e75665fe58d0f3fd5db400959274296e9"}, + {file = "protobuf-4.25.0-cp39-cp39-win32.whl", hash = "sha256:63714e79b761a37048c9701a37438aa29945cd2417a97076048232c1df07b701"}, + {file = "protobuf-4.25.0-cp39-cp39-win_amd64.whl", hash = "sha256:d94a33db8b7ddbd0af7c467475fb9fde0c705fb315a8433c0e2020942b863a1f"}, + {file = "protobuf-4.25.0-py3-none-any.whl", hash = "sha256:1a53d6f64b00eecf53b65ff4a8c23dc95df1fa1e97bb06b8122e5a64f49fc90a"}, + {file = "protobuf-4.25.0.tar.gz", hash = "sha256:68f7caf0d4f012fd194a301420cf6aa258366144d814f358c5b32558228afa7c"}, ] [[package]] @@ -3293,22 +3281,22 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] [[package]] name = "pyaudio" -version = "0.2.13" +version = "0.2.14" description = "Cross-platform audio I/O with PortAudio" optional = false python-versions = "*" files = [ - {file = "PyAudio-0.2.13-cp310-cp310-win32.whl", hash = "sha256:48e29537ea22ae2ae323eebe297bfb2683831cee4f20d96964e131f65ab2161d"}, - {file = "PyAudio-0.2.13-cp310-cp310-win_amd64.whl", hash = "sha256:87137cfd0ef8608a2a383be3f6996f59505e322dab9d16531f14cf542fa294f1"}, - {file = "PyAudio-0.2.13-cp311-cp311-win32.whl", hash = "sha256:13915faaa780e6bbbb6d745ef0e761674fd461b1b1b3f9c1f57042a534bfc0c3"}, - {file = "PyAudio-0.2.13-cp311-cp311-win_amd64.whl", hash = "sha256:59cc3cc5211b729c7854e3989058a145872cc58b1a7b46c6d4d88448a343d890"}, - {file = "PyAudio-0.2.13-cp37-cp37m-win32.whl", hash = "sha256:d294e3f85b2238649b1ff49ce3412459a8a312569975a89d14646536362d7576"}, - {file = "PyAudio-0.2.13-cp37-cp37m-win_amd64.whl", hash = "sha256:ff7f5e44ef51fe61da1e09c6f632f0b5808198edd61b363855cc7dd03bf4a8ac"}, - {file = "PyAudio-0.2.13-cp38-cp38-win32.whl", hash = "sha256:c6b302b048c054b7463936d8ba884b73877dc47012f3c94665dba92dd658ae04"}, - {file = "PyAudio-0.2.13-cp38-cp38-win_amd64.whl", hash = "sha256:1505d766ee718df6f5a18b73ac42307ba1cb4d2c0397873159254a34f67515d6"}, - {file = "PyAudio-0.2.13-cp39-cp39-win32.whl", hash = "sha256:eb128e4a6ea9b98d9a31f33c44978885af27dbe8ae53d665f8790cbfe045517e"}, - {file = "PyAudio-0.2.13-cp39-cp39-win_amd64.whl", hash = "sha256:910ef09225cce227adbba92622d4a3e3c8375117f7dd64039f287d9ffc0e02a1"}, - {file = "PyAudio-0.2.13.tar.gz", hash = "sha256:26bccc81e4243d1c0ff5487e6b481de6329fcd65c79365c267cef38f363a2b56"}, + {file = "PyAudio-0.2.14-cp310-cp310-win32.whl", hash = "sha256:126065b5e82a1c03ba16e7c0404d8f54e17368836e7d2d92427358ad44fefe61"}, + {file = "PyAudio-0.2.14-cp310-cp310-win_amd64.whl", hash = "sha256:2a166fc88d435a2779810dd2678354adc33499e9d4d7f937f28b20cc55893e83"}, + {file = "PyAudio-0.2.14-cp311-cp311-win32.whl", hash = "sha256:506b32a595f8693811682ab4b127602d404df7dfc453b499c91a80d0f7bad289"}, + {file = "PyAudio-0.2.14-cp311-cp311-win_amd64.whl", hash = "sha256:bbeb01d36a2f472ae5ee5e1451cacc42112986abe622f735bb870a5db77cf903"}, + {file = "PyAudio-0.2.14-cp312-cp312-win32.whl", hash = "sha256:5fce4bcdd2e0e8c063d835dbe2860dac46437506af509353c7f8114d4bacbd5b"}, + {file = "PyAudio-0.2.14-cp312-cp312-win_amd64.whl", hash = "sha256:12f2f1ba04e06ff95d80700a78967897a489c05e093e3bffa05a84ed9c0a7fa3"}, + {file = "PyAudio-0.2.14-cp38-cp38-win32.whl", hash = "sha256:858caf35b05c26d8fc62f1efa2e8f53d5fa1a01164842bd622f70ddc41f55000"}, + {file = "PyAudio-0.2.14-cp38-cp38-win_amd64.whl", hash = "sha256:2dac0d6d675fe7e181ba88f2de88d321059b69abd52e3f4934a8878e03a7a074"}, + {file = "PyAudio-0.2.14-cp39-cp39-win32.whl", hash = "sha256:f745109634a7c19fa4d6b8b7d6967c3123d988c9ade0cd35d4295ee1acdb53e9"}, + {file = "PyAudio-0.2.14-cp39-cp39-win_amd64.whl", hash = "sha256:009f357ee5aa6bc8eb19d69921cd30e98c42cddd34210615d592a71d09c4bd57"}, + {file = "PyAudio-0.2.14.tar.gz", hash = "sha256:78dfff3879b4994d1f4fc6485646a57755c6ee3c19647a491f790a0895bd2f87"}, ] [package.extras] @@ -3860,13 +3848,13 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale [[package]] name = "pytest-cpp" -version = "2.4.0" +version = "2.5.0" description = "Use pytest's runner to discover and execute C++ tests" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-cpp-2.4.0.tar.gz", hash = "sha256:dcb8b09d4c714fc7f778dc40a7c2c47e73cc50280d7f9bba3bdd3ca98abd4685"}, - {file = "pytest_cpp-2.4.0-py3-none-any.whl", hash = "sha256:e7c5f40b70b00cc09d672a1584e35beb9b9553512cdd4b1d1f99468747b3bc31"}, + {file = "pytest-cpp-2.5.0.tar.gz", hash = "sha256:695604baa21bc95291bb4ea7263a7aa960753de57c2d17d224c4652fbcf65cdc"}, + {file = "pytest_cpp-2.5.0-py3-none-any.whl", hash = "sha256:137bcaa6487307b4c362245fcd4abf35de64ee85e6375f4d06cd31e6a64f9701"}, ] [package.dependencies] @@ -4201,28 +4189,28 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "ruff" -version = "0.1.3" -description = "An extremely fast Python linter, written in Rust." +version = "0.1.4" +description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.1.3-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:b46d43d51f7061652eeadb426a9e3caa1e0002470229ab2fc19de8a7b0766901"}, - {file = "ruff-0.1.3-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:b8afeb9abd26b4029c72adc9921b8363374f4e7edb78385ffaa80278313a15f9"}, - {file = "ruff-0.1.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca3cf365bf32e9ba7e6db3f48a4d3e2c446cd19ebee04f05338bc3910114528b"}, - {file = "ruff-0.1.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4874c165f96c14a00590dcc727a04dca0cfd110334c24b039458c06cf78a672e"}, - {file = "ruff-0.1.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eec2dd31eed114e48ea42dbffc443e9b7221976554a504767ceaee3dd38edeb8"}, - {file = "ruff-0.1.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:dc3ec4edb3b73f21b4aa51337e16674c752f1d76a4a543af56d7d04e97769613"}, - {file = "ruff-0.1.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e3de9ed2e39160800281848ff4670e1698037ca039bda7b9274f849258d26ce"}, - {file = "ruff-0.1.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c595193881922cc0556a90f3af99b1c5681f0c552e7a2a189956141d8666fe8"}, - {file = "ruff-0.1.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f75e670d529aa2288cd00fc0e9b9287603d95e1536d7a7e0cafe00f75e0dd9d"}, - {file = "ruff-0.1.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:76dd49f6cd945d82d9d4a9a6622c54a994689d8d7b22fa1322983389b4892e20"}, - {file = "ruff-0.1.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:918b454bc4f8874a616f0d725590277c42949431ceb303950e87fef7a7d94cb3"}, - {file = "ruff-0.1.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d8859605e729cd5e53aa38275568dbbdb4fe882d2ea2714c5453b678dca83784"}, - {file = "ruff-0.1.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0b6c55f5ef8d9dd05b230bb6ab80bc4381ecb60ae56db0330f660ea240cb0d4a"}, - {file = "ruff-0.1.3-py3-none-win32.whl", hash = "sha256:3e7afcbdcfbe3399c34e0f6370c30f6e529193c731b885316c5a09c9e4317eef"}, - {file = "ruff-0.1.3-py3-none-win_amd64.whl", hash = "sha256:7a18df6638cec4a5bd75350639b2bb2a2366e01222825562c7346674bdceb7ea"}, - {file = "ruff-0.1.3-py3-none-win_arm64.whl", hash = "sha256:12fd53696c83a194a2db7f9a46337ce06445fb9aa7d25ea6f293cf75b21aca9f"}, - {file = "ruff-0.1.3.tar.gz", hash = "sha256:3ba6145369a151401d5db79f0a47d50e470384d0d89d0d6f7fab0b589ad07c34"}, + {file = "ruff-0.1.4-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:864958706b669cce31d629902175138ad8a069d99ca53514611521f532d91495"}, + {file = "ruff-0.1.4-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:9fdd61883bb34317c788af87f4cd75dfee3a73f5ded714b77ba928e418d6e39e"}, + {file = "ruff-0.1.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4eaca8c9cc39aa7f0f0d7b8fe24ecb51232d1bb620fc4441a61161be4a17539"}, + {file = "ruff-0.1.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a9a1301dc43cbf633fb603242bccd0aaa34834750a14a4c1817e2e5c8d60de17"}, + {file = "ruff-0.1.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e8db8ab6f100f02e28b3d713270c857d370b8d61871d5c7d1702ae411df683"}, + {file = "ruff-0.1.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:80fea754eaae06335784b8ea053d6eb8e9aac75359ebddd6fee0858e87c8d510"}, + {file = "ruff-0.1.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6bc02a480d4bfffd163a723698da15d1a9aec2fced4c06f2a753f87f4ce6969c"}, + {file = "ruff-0.1.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9862811b403063765b03e716dac0fda8fdbe78b675cd947ed5873506448acea4"}, + {file = "ruff-0.1.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58826efb8b3efbb59bb306f4b19640b7e366967a31c049d49311d9eb3a4c60cb"}, + {file = "ruff-0.1.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:fdfd453fc91d9d86d6aaa33b1bafa69d114cf7421057868f0b79104079d3e66e"}, + {file = "ruff-0.1.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e8791482d508bd0b36c76481ad3117987301b86072158bdb69d796503e1c84a8"}, + {file = "ruff-0.1.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:01206e361021426e3c1b7fba06ddcb20dbc5037d64f6841e5f2b21084dc51800"}, + {file = "ruff-0.1.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:645591a613a42cb7e5c2b667cbefd3877b21e0252b59272ba7212c3d35a5819f"}, + {file = "ruff-0.1.4-py3-none-win32.whl", hash = "sha256:99908ca2b3b85bffe7e1414275d004917d1e0dfc99d497ccd2ecd19ad115fd0d"}, + {file = "ruff-0.1.4-py3-none-win_amd64.whl", hash = "sha256:1dfd6bf8f6ad0a4ac99333f437e0ec168989adc5d837ecd38ddb2cc4a2e3db8a"}, + {file = "ruff-0.1.4-py3-none-win_arm64.whl", hash = "sha256:d98ae9ebf56444e18a3e3652b3383204748f73e247dea6caaf8b52d37e6b32da"}, + {file = "ruff-0.1.4.tar.gz", hash = "sha256:21520ecca4cc555162068d87c747b8f95e1e95f8ecfcbbe59e8dd00710586315"}, ] [[package]] @@ -4481,27 +4469,6 @@ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] -[[package]] -name = "setuptools-scm" -version = "8.0.4" -description = "the blessed package to manage your versions by scm tags" -optional = false -python-versions = ">=3.8" -files = [ - {file = "setuptools-scm-8.0.4.tar.gz", hash = "sha256:b5f43ff6800669595193fd09891564ee9d1d7dcb196cab4b2506d53a2e1c95c7"}, - {file = "setuptools_scm-8.0.4-py3-none-any.whl", hash = "sha256:b47844cd2a84b83b3187a5782c71128c28b4c94cad8bfb871da2784a5cb54c4f"}, -] - -[package.dependencies] -packaging = ">=20" -setuptools = "*" -typing-extensions = "*" - -[package.extras] -docs = ["entangled-cli[rich]", "mkdocs", "mkdocs-entangled-plugin", "mkdocs-material", "mkdocstrings[python]", "pygments"] -rich = ["rich"] -test = ["build", "pytest", "rich", "wheel"] - [[package]] name = "shapely" version = "2.0.2" From 9118973ed03c1ae1d40cf69a29507ec2cc78efd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 7 Nov 2023 14:17:37 -0500 Subject: [PATCH 104/133] Farmville model (#30392) * slightly different * Revert "slightly different" This reverts commit 8a470ecab40c295f3b8c777b82cb7a22890d116e. * d09c9c88-1797-4ed5-ab2d-9dca5b12340b/700 * Update power draw * Revert "Update power draw" This reverts commit 1c95b663ec9c507604dd8580ff6386497b5391a8. * Update 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 8325cc947e3cba5..e2897b08a558bff 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:6330383805f2e64e750f61c47660d2ec8522f55d84217c0520584d2e0d7c3faf -size 52939093 +oid sha256:0b7184d46dc2ba3f84eb748252634205105a3742bac29942ae4380b0332fa850 +size 52524758 diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index ddf515181d00473..977f19e7bcadebd 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -d1212a1ac9119a1be33f2e375b1421344379ec08 +35a05ff1b68062c9478b2adfe96f1c294bee1b6c From d2edc239fdc5d81a798c723052e8a118aff2c39d Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 7 Nov 2023 11:27:56 -0800 Subject: [PATCH 105/133] jenkins: disable ciui for now --- selfdrive/test/setup_device_ci.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/selfdrive/test/setup_device_ci.sh b/selfdrive/test/setup_device_ci.sh index ca458f2a79c41e2..c34e097f73edb6f 100755 --- a/selfdrive/test/setup_device_ci.sh +++ b/selfdrive/test/setup_device_ci.sh @@ -43,11 +43,11 @@ while true; do sudo systemctl start ssh fi - if ! pgrep -f 'ciui.py' > /dev/null 2>&1; then - echo 'starting UI' - cp $SOURCE_DIR/selfdrive/test/ciui.py /data/ - /data/ciui.py & - fi + #if ! pgrep -f 'ciui.py' > /dev/null 2>&1; then + # echo 'starting UI' + # cp $SOURCE_DIR/selfdrive/test/ciui.py /data/ + # /data/ciui.py & + #fi sleep 5s done From c9915ceba9d352af6ebb12b1592fc568fe38ebc5 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Tue, 7 Nov 2023 16:16:23 -0500 Subject: [PATCH 106/133] Codecov: ignore selfdrive/test (#30407) * ignore * fix that --- codecov.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/codecov.yml b/codecov.yml index da57bb01ccfc8ed..686d9b03f772758 100644 --- a/codecov.yml +++ b/codecov.yml @@ -7,4 +7,5 @@ coverage: patch: off ignore: - - "**/test_*.py" \ No newline at end of file + - "**/test_*.py" + - "selfdrive/test/**" \ No newline at end of file From 37ba6d85039e7c4bc19d272666f6c24d8b6fe6bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 7 Nov 2023 13:29:30 -0800 Subject: [PATCH 107/133] Update RELEASES.md --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 96028a9787ebc35..0efa3d3918958b0 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -2,6 +2,8 @@ Version 0.9.5 (2023-XX-XX) ======================== * New driving model * Improved navigate on openpilot performance using navigation instructions as an additional model input + * Do lateral planning inside the model + * New vision transformer architecture * Cadillac Escalade ESV 2019 support thanks to twilsonco! * Hyundai Azera 2022 support thanks to sunnyhaibin! * Hyundai Azera Hybrid 2020 support thanks to chanhojung and haram-KONA! From 0f6b16d1e08b05826d2ce93295e510842eef4b53 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 8 Nov 2023 07:22:43 +0800 Subject: [PATCH 108/133] ui/wifi.cc: fix small QPixmap leak (#30395) fix QPixmap leaks --- selfdrive/ui/qt/widgets/wifi.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/ui/qt/widgets/wifi.cc b/selfdrive/ui/qt/widgets/wifi.cc index ed5825ab775861b..9c5289a22d8c29e 100644 --- a/selfdrive/ui/qt/widgets/wifi.cc +++ b/selfdrive/ui/qt/widgets/wifi.cc @@ -18,8 +18,8 @@ WiFiPromptWidget::WiFiPromptWidget(QWidget *parent) : QFrame(parent) { title_layout->setSpacing(32); { QLabel *icon = new QLabel; - QPixmap *pixmap = new QPixmap("../assets/offroad/icon_wifi_strength_full.svg"); - icon->setPixmap(pixmap->scaledToWidth(80, Qt::SmoothTransformation)); + QPixmap pixmap("../assets/offroad/icon_wifi_strength_full.svg"); + icon->setPixmap(pixmap.scaledToWidth(80, Qt::SmoothTransformation)); title_layout->addWidget(icon); QLabel *title = new QLabel(tr("Setup Wi-Fi")); @@ -68,8 +68,8 @@ WiFiPromptWidget::WiFiPromptWidget(QWidget *parent) : QFrame(parent) { title_layout->addStretch(); QLabel *icon = new QLabel; - QPixmap *pixmap = new QPixmap("../assets/offroad/icon_wifi_uploading.svg"); - icon->setPixmap(pixmap->scaledToWidth(120, Qt::SmoothTransformation)); + QPixmap pixmap("../assets/offroad/icon_wifi_uploading.svg"); + icon->setPixmap(pixmap.scaledToWidth(120, Qt::SmoothTransformation)); title_layout->addWidget(icon); } uploading_layout->addLayout(title_layout); From c419376bbde634801d0bdf247d564a5b8ecff795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20R=C4=85czy?= Date: Tue, 7 Nov 2023 15:48:13 -0800 Subject: [PATCH 109/133] controlsd: reset axes in joystick mode if message is old (#30409) Reset joystick if it wasnt received after 0.2 sec --- selfdrive/controls/controlsd.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index d800d895d36b00d..437cf2d7ce6637b 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -619,11 +619,18 @@ def state_control(self, CS): else: lac_log = log.ControlsState.LateralDebugState.new_message() if self.sm.rcv_frame['testJoystick'] > 0: + # reset joystick if it hasn't been received in a while + should_reset_joystick = (self.sm.frame - self.sm.rcv_frame['testJoystick'])*DT_CTRL > 0.2 + if not should_reset_joystick: + joystick_axes = self.sm['testJoystick'].axes + else: + joystick_axes = [0.0, 0.0] + if CC.longActive: - actuators.accel = 4.0*clip(self.sm['testJoystick'].axes[0], -1, 1) + actuators.accel = 4.0*clip(joystick_axes[0], -1, 1) if CC.latActive: - steer = clip(self.sm['testJoystick'].axes[1], -1, 1) + steer = clip(joystick_axes[1], -1, 1) # max angle is 45 for angle-based cars, max curvature is 0.02 actuators.steer, actuators.steeringAngleDeg, actuators.curvature = steer, steer * 45., steer * -0.02 From aec7cea30d48dc8915eea38c86de7d4effa0548d Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Tue, 7 Nov 2023 20:35:44 -0500 Subject: [PATCH 110/133] Pytest: tici mark for skipping on-device tests (#30412) * mark tici * not those ones * missed that one * add those * add pypoetry * oops --- conftest.py | 8 ++++++++ pyproject.toml | 3 ++- release/files_common | 1 + selfdrive/boardd/tests/test_pandad.py | 6 +++--- selfdrive/manager/test/test_manager.py | 2 ++ selfdrive/modeld/tests/test_modeld.py | 1 + selfdrive/navd/tests/test_map_renderer.py | 6 ++---- selfdrive/test/test_onroad.py | 2 ++ selfdrive/test/test_time_to_onroad.py | 2 ++ selfdrive/test/test_updated.py | 2 ++ system/camerad/test/test_camerad.py | 6 ++---- system/hardware/tici/tests/test_hardware.py | 7 +++---- system/hardware/tici/tests/test_power_draw.py | 9 +++------ system/loggerd/tests/test_encoder.py | 8 ++------ system/sensord/rawgps/test_rawgps.py | 6 ++---- system/sensord/tests/test_pigeond.py | 7 ++----- system/sensord/tests/test_sensord.py | 6 ++---- tools/gpstest/test_gps.py | 6 ++---- tools/gpstest/test_gps_qcom.py | 6 ++---- 19 files changed, 45 insertions(+), 49 deletions(-) diff --git a/conftest.py b/conftest.py index ee46436d3c8bffe..085ad5b28af9944 100644 --- a/conftest.py +++ b/conftest.py @@ -2,6 +2,7 @@ import pytest from openpilot.common.prefix import OpenpilotPrefix +from openpilot.system.hardware import TICI @pytest.fixture(scope="function", autouse=True) @@ -31,3 +32,10 @@ def openpilot_class_fixture(): os.environ.clear() os.environ.update(starting_env) + + +def pytest_collection_modifyitems(config, items): + skipper = pytest.mark.skip(reason="Skipping tici test on PC") + for item in items: + if not TICI and "tici" in item.keywords: + item.add_marker(skipper) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index c83669898f06714..71b677fbb7fd0b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,8 @@ addopts = "--ignore=openpilot/ --ignore=cereal/ --ignore=opendbc/ --ignore=panda python_files = "test_*.py" #timeout = "30" # you get this long by default markers = [ - "slow: tests that take awhile to run and can be skipped with -m 'not slow'" + "slow: tests that take awhile to run and can be skipped with -m 'not slow'", + "tici: tests that are only meant to run on the C3/C3X", ] testpaths = [ "common", diff --git a/release/files_common b/release/files_common index 9076f440d59d611..5a076f2b1a37c49 100644 --- a/release/files_common +++ b/release/files_common @@ -6,6 +6,7 @@ launch_openpilot.sh Jenkinsfile SConstruct +pyproject.toml README.md RELEASES.md diff --git a/selfdrive/boardd/tests/test_pandad.py b/selfdrive/boardd/tests/test_pandad.py index c1bf22f1464c60f..4036766faa737f6 100755 --- a/selfdrive/boardd/tests/test_pandad.py +++ b/selfdrive/boardd/tests/test_pandad.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import os +import pytest import time import unittest @@ -8,17 +9,16 @@ from openpilot.common.gpio import gpio_set, gpio_init from panda import Panda, PandaDFU, PandaProtocolMismatch from openpilot.selfdrive.manager.process_config import managed_processes -from openpilot.system.hardware import HARDWARE, PC +from openpilot.system.hardware import HARDWARE from openpilot.system.hardware.tici.pins import GPIO HERE = os.path.dirname(os.path.realpath(__file__)) +@pytest.mark.tici class TestPandad(unittest.TestCase): def setUp(self): - if PC: - raise unittest.SkipTest("needs a panda") # ensure panda is up if len(Panda.list()) == 0: self._run_test(60) diff --git a/selfdrive/manager/test/test_manager.py b/selfdrive/manager/test/test_manager.py index d4d4e64f78e95ee..0fa186baffde960 100755 --- a/selfdrive/manager/test/test_manager.py +++ b/selfdrive/manager/test/test_manager.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import os +import pytest import signal import time import unittest @@ -17,6 +18,7 @@ BLACKLIST_PROCS = ['manage_athenad', 'pandad', 'pigeond'] +@pytest.mark.tici class TestManager(unittest.TestCase): def setUp(self): os.environ['PASSIVE'] = '0' diff --git a/selfdrive/modeld/tests/test_modeld.py b/selfdrive/modeld/tests/test_modeld.py index 7ae6d5308fca211..e010f6cfd61a890 100755 --- a/selfdrive/modeld/tests/test_modeld.py +++ b/selfdrive/modeld/tests/test_modeld.py @@ -13,6 +13,7 @@ IMG = np.zeros(int(tici_f_frame_size[0]*tici_f_frame_size[1]*(3/2)), dtype=np.uint8) IMG_BYTES = IMG.flatten().tobytes() + class TestModeld(unittest.TestCase): def setUp(self): diff --git a/selfdrive/navd/tests/test_map_renderer.py b/selfdrive/navd/tests/test_map_renderer.py index c4c9785cb16f383..dbd6add995889ee 100755 --- a/selfdrive/navd/tests/test_map_renderer.py +++ b/selfdrive/navd/tests/test_map_renderer.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import numpy as np import os +import pytest import unittest import requests import threading @@ -10,7 +11,6 @@ from typing import Any from cereal.visionipc import VisionIpcClient, VisionStreamType from openpilot.selfdrive.manager.process_config import managed_processes -from openpilot.system.hardware import TICI LLK_DECIMATION = 10 CACHE_PATH = "/data/mbgl-cache-navd.db" @@ -189,10 +189,8 @@ def test_recover_from_no_internet(self): self._run_test(True, LOCATION2_REPEATED) + @pytest.mark.tici def test_render_time_distribution(self): - if not TICI: - raise unittest.SkipTest - self._setup_test() # from location1 -> location2 and back locations = np.array([*np.linspace(LOCATION1, LOCATION2, 2000), *np.linspace(LOCATION2, LOCATION1, 2000)]).tolist() diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 30632c7cd6c248d..0e9d207da379cc7 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -5,6 +5,7 @@ import os import pathlib import psutil +import pytest import shutil import subprocess import time @@ -98,6 +99,7 @@ def cputime_total(ct): return ct.cpuUser + ct.cpuSystem + ct.cpuChildrenUser + ct.cpuChildrenSystem +@pytest.mark.tici class TestOnroad(unittest.TestCase): @classmethod diff --git a/selfdrive/test/test_time_to_onroad.py b/selfdrive/test/test_time_to_onroad.py index 501ce16b6455d1d..cc2cc6514eb7f5a 100755 --- a/selfdrive/test/test_time_to_onroad.py +++ b/selfdrive/test/test_time_to_onroad.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import os +import pytest import time import subprocess @@ -9,6 +10,7 @@ from openpilot.selfdrive.test.helpers import set_params_enabled +@pytest.mark.tici def test_time_to_onroad(): # launch set_params_enabled() diff --git a/selfdrive/test/test_updated.py b/selfdrive/test/test_updated.py index e679cd2c3b81ec9..dd79e03de4a5e8f 100755 --- a/selfdrive/test/test_updated.py +++ b/selfdrive/test/test_updated.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import datetime import os +import pytest import time import tempfile import unittest @@ -13,6 +14,7 @@ from openpilot.common.params import Params +@pytest.mark.tici class TestUpdated(unittest.TestCase): def setUp(self): diff --git a/system/camerad/test/test_camerad.py b/system/camerad/test/test_camerad.py index b680c1df67446d3..ad3a9fdc91d5ccf 100755 --- a/system/camerad/test/test_camerad.py +++ b/system/camerad/test/test_camerad.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import pytest import time import unittest import numpy as np @@ -8,7 +9,6 @@ from cereal import log from cereal.services import SERVICE_LIST from openpilot.selfdrive.manager.process_config import managed_processes -from openpilot.system.hardware import TICI TEST_TIMESPAN = 30 LAG_FRAME_TOLERANCE = {log.FrameData.ImageSensor.ar0231: 0.5, # ARs use synced pulses for frame starts @@ -19,12 +19,10 @@ CAMERAS = ('roadCameraState', 'driverCameraState', 'wideRoadCameraState') +@pytest.mark.tici class TestCamerad(unittest.TestCase): @classmethod def setUpClass(cls): - if not TICI: - raise unittest.SkipTest - # run camerad and record logs managed_processes['camerad'].start() time.sleep(3) diff --git a/system/hardware/tici/tests/test_hardware.py b/system/hardware/tici/tests/test_hardware.py index 7d377ac3fbe2e2e..4abc86107b321fe 100755 --- a/system/hardware/tici/tests/test_hardware.py +++ b/system/hardware/tici/tests/test_hardware.py @@ -1,20 +1,19 @@ #!/usr/bin/env python3 +import pytest import time import unittest import numpy as np -from openpilot.system.hardware import TICI from openpilot.system.hardware.tici.hardware import Tici HARDWARE = Tici() + +@pytest.mark.tici class TestHardware(unittest.TestCase): @classmethod def setUpClass(cls): - if not TICI: - raise unittest.SkipTest - HARDWARE.initialize_hardware() HARDWARE.set_power_save(False) diff --git a/system/hardware/tici/tests/test_power_draw.py b/system/hardware/tici/tests/test_power_draw.py index 64119357499b54d..c61d67e79dff3be 100755 --- a/system/hardware/tici/tests/test_power_draw.py +++ b/system/hardware/tici/tests/test_power_draw.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import pytest import unittest import time import threading @@ -9,7 +10,7 @@ import cereal.messaging as messaging from cereal.services import SERVICE_LIST -from openpilot.system.hardware import HARDWARE, TICI +from openpilot.system.hardware import HARDWARE from openpilot.system.hardware.tici.power_monitor import get_power from openpilot.selfdrive.manager.process_config import managed_processes from openpilot.selfdrive.manager.manager import manager_cleanup @@ -44,13 +45,9 @@ def send_llk_msg(done): time.sleep(1/20.) +@pytest.mark.tici class TestPowerDraw(unittest.TestCase): - @classmethod - def setUpClass(cls): - if not TICI: - raise unittest.SkipTest - def setUp(self): HARDWARE.initialize_hardware() HARDWARE.set_power_save(False) diff --git a/system/loggerd/tests/test_encoder.py b/system/loggerd/tests/test_encoder.py index c46ac31b7fb32c3..bd076dc5f3177a3 100755 --- a/system/loggerd/tests/test_encoder.py +++ b/system/loggerd/tests/test_encoder.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import math import os +import pytest import random import shutil import subprocess @@ -31,14 +32,9 @@ FILE_SIZE_TOLERANCE = 0.5 +@pytest.mark.tici # TODO: all of loggerd should work on PC class TestEncoder(unittest.TestCase): - # TODO: all of loggerd should work on PC - @classmethod - def setUpClass(cls): - if not TICI: - raise unittest.SkipTest - def setUp(self): self._clear_logs() os.environ["LOGGERD_TEST"] = "1" diff --git a/system/sensord/rawgps/test_rawgps.py b/system/sensord/rawgps/test_rawgps.py index 2a0ee656e2a5e7a..364243813211577 100755 --- a/system/sensord/rawgps/test_rawgps.py +++ b/system/sensord/rawgps/test_rawgps.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import os +import pytest import json import time import datetime @@ -7,19 +8,16 @@ import subprocess import cereal.messaging as messaging -from openpilot.system.hardware import TICI from openpilot.system.sensord.rawgps.rawgpsd import at_cmd, wait_for_modem from openpilot.selfdrive.manager.process_config import managed_processes GOOD_SIGNAL = bool(int(os.getenv("GOOD_SIGNAL", '0'))) +@pytest.mark.tici class TestRawgpsd(unittest.TestCase): @classmethod def setUpClass(cls): - if not TICI: - raise unittest.SkipTest - os.system("sudo systemctl start systemd-resolved") os.system("sudo systemctl restart ModemManager lte") wait_for_modem() diff --git a/system/sensord/tests/test_pigeond.py b/system/sensord/tests/test_pigeond.py index b23afcb07c737b2..f2ab43bbb7f9c58 100755 --- a/system/sensord/tests/test_pigeond.py +++ b/system/sensord/tests/test_pigeond.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import pytest import time import unittest @@ -7,16 +8,12 @@ from openpilot.common.gpio import gpio_read from openpilot.selfdrive.test.helpers import with_processes from openpilot.selfdrive.manager.process_config import managed_processes -from openpilot.system.hardware import TICI from openpilot.system.hardware.tici.pins import GPIO # TODO: test TTFF when we have good A-GNSS +@pytest.mark.tici class TestPigeond(unittest.TestCase): - @classmethod - def setUpClass(cls): - if not TICI: - raise unittest.SkipTest def tearDown(self): managed_processes['pigeond'].stop() diff --git a/system/sensord/tests/test_sensord.py b/system/sensord/tests/test_sensord.py index fba3ef79a4412d3..090524807150c32 100755 --- a/system/sensord/tests/test_sensord.py +++ b/system/sensord/tests/test_sensord.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import os +import pytest import time import unittest import numpy as np @@ -10,7 +11,6 @@ from cereal.services import SERVICE_LIST from openpilot.common.gpio import get_irqs_for_action from openpilot.common.timeout import Timeout -from openpilot.system.hardware import TICI from openpilot.selfdrive.manager.process_config import managed_processes BMX = { @@ -98,12 +98,10 @@ def read_sensor_events(duration_sec): return {k: v for k, v in events.items() if len(v) > 0} +@pytest.mark.tici class TestSensord(unittest.TestCase): @classmethod def setUpClass(cls): - if not TICI: - raise unittest.SkipTest - # enable LSM self test os.environ["LSM_SELF_TEST"] = "1" diff --git a/tools/gpstest/test_gps.py b/tools/gpstest/test_gps.py index 98f1ad84b8ca8bc..bbd53ebfffb0947 100755 --- a/tools/gpstest/test_gps.py +++ b/tools/gpstest/test_gps.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import pytest import time import unittest import struct @@ -6,7 +7,6 @@ from openpilot.common.params import Params import cereal.messaging as messaging import openpilot.system.sensord.pigeond as pd -from openpilot.system.hardware import TICI from openpilot.selfdrive.test.helpers import with_processes @@ -107,12 +107,10 @@ def verify_time_to_first_fix(pigeon): assert ttff < 40, f"Time to first fix > 40s, {ttff}" +@pytest.mark.tici class TestGPS(unittest.TestCase): @classmethod def setUpClass(cls): - if not TICI: - raise unittest.SkipTest - ublox_available = Params().get_bool("UbloxAvailable") if not ublox_available: raise unittest.SkipTest diff --git a/tools/gpstest/test_gps_qcom.py b/tools/gpstest/test_gps_qcom.py index c3996717159ca72..2ea5556684bf7f8 100755 --- a/tools/gpstest/test_gps_qcom.py +++ b/tools/gpstest/test_gps_qcom.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 +import pytest import time import unittest import subprocess as sp from openpilot.common.params import Params -from openpilot.system.hardware import TICI import cereal.messaging as messaging from openpilot.selfdrive.manager.process_config import managed_processes @@ -30,12 +30,10 @@ def wait_for_location(socket, timeout): continue +@pytest.mark.tici 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 From 1d7caa80aab25bf8604a9cc8848234b8c25cda11 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 7 Nov 2023 20:04:46 -0800 Subject: [PATCH 111/133] bump panda (#30415) bump --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index f3bdfdd4354ccc3..fa04f476000e8cf 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit f3bdfdd4354ccc3a512dc289dc038d5b30d1fec2 +Subproject commit fa04f476000e8cfff72780212b115b5ab059b079 From 84d2fa68f70a7e1e056348b6d00576d2f34bacf1 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Wed, 8 Nov 2023 10:06:30 -0800 Subject: [PATCH 112/133] modeld: handle division by zero (#30411) * modeld: avoid division by zero * undefined at 0 --- selfdrive/modeld/fill_model_msg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/modeld/fill_model_msg.py b/selfdrive/modeld/fill_model_msg.py index 2b8a72b9beb4aa0..7434e9428706cd9 100644 --- a/selfdrive/modeld/fill_model_msg.py +++ b/selfdrive/modeld/fill_model_msg.py @@ -92,7 +92,7 @@ def fill_model_msg(msg: capnp._DynamicStructBuilder, net_output_data: Dict[str, # interpolate to find `t` for the current xidx current_x_val = plan_x[tidx] next_x_val = plan_x[tidx+1] - p = (ModelConstants.X_IDXS[xidx] - current_x_val) / (next_x_val - current_x_val) + p = (ModelConstants.X_IDXS[xidx] - current_x_val) / (next_x_val - current_x_val) if abs(next_x_val - current_x_val) > 1e-9 else float('nan') PLAN_T_IDXS[xidx] = p * ModelConstants.T_IDXS[tidx+1] + (1 - p) * ModelConstants.T_IDXS[tidx] # lane lines From 4967377b3fcfddc1099cd82cd8192893271ad1f1 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 8 Nov 2023 11:05:23 -0800 Subject: [PATCH 113/133] Update RELEASES.md --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 0efa3d3918958b0..1d88480278c7cdd 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,4 +1,4 @@ -Version 0.9.5 (2023-XX-XX) +Version 0.9.5 (2023-11-16) ======================== * New driving model * Improved navigate on openpilot performance using navigation instructions as an additional model input From d02dd50749c8dabc1cd3385bdf2cf3fb7cb7ac63 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Wed, 8 Nov 2023 16:43:32 -0500 Subject: [PATCH 114/133] Pytest: consistent codecov (#30408) * seed only * random seed * ignore version.py * increase max examples * increase default max examples --- .github/workflows/selfdrive_tests.yaml | 2 +- codecov.yml | 3 ++- conftest.py | 3 +++ selfdrive/car/tests/test_car_interfaces.py | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index bd6885cf5b5c341..a83b495f1178b47 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -27,7 +27,7 @@ env: RUN_CL: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONWARNINGS=error -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $CL_BASE_IMAGE /bin/sh -c UNIT_TEST: coverage run --append -m unittest discover - PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5 + PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5 --hypothesis-seed 0 jobs: build_release: diff --git a/codecov.yml b/codecov.yml index 686d9b03f772758..40d03dcd7a9b399 100644 --- a/codecov.yml +++ b/codecov.yml @@ -8,4 +8,5 @@ coverage: ignore: - "**/test_*.py" - - "selfdrive/test/**" \ No newline at end of file + - "selfdrive/test/**" + - "system/version.py" # codecov changes depending on if we are in a branch or not \ No newline at end of file diff --git a/conftest.py b/conftest.py index 085ad5b28af9944..08ddb0d1ea9adc1 100644 --- a/conftest.py +++ b/conftest.py @@ -1,5 +1,6 @@ import os import pytest +import random from openpilot.common.prefix import OpenpilotPrefix from openpilot.system.hardware import TICI @@ -9,6 +10,8 @@ def openpilot_function_fixture(): starting_env = dict(os.environ) + random.seed(0) + # setup a clean environment for each test with OpenpilotPrefix(): prefix = os.environ["OPENPILOT_PREFIX"] diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 5fa1a028979a3c7..a920bd45da15876 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -18,7 +18,7 @@ ALL_ECUS = list({ecu for ecus in FW_VERSIONS.values() for ecu in ecus.keys()}) -MAX_EXAMPLES = int(os.environ.get('MAX_EXAMPLES', '5')) +MAX_EXAMPLES = int(os.environ.get('MAX_EXAMPLES', '20')) def get_fuzzy_car_interface_args(draw: DrawType) -> dict: From fa9d3ec1f5c3ca0b32d61a1fdd410cd7bb59c932 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Wed, 8 Nov 2023 17:15:15 -0500 Subject: [PATCH 115/133] build_release: increase timeout (#30416) inc timeout --- .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 a83b495f1178b47..3efdb8a98b219ee 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -54,7 +54,7 @@ jobs: cd $STRIPPED_DIR ${{ env.RUN }} "CI=1 python selfdrive/manager/build.py" - name: Run tests - timeout-minutes: 2 + timeout-minutes: 2.5 run: | cd $STRIPPED_DIR ${{ env.RUN }} "release/check-dirty.sh && \ From 844cbd95e73b9ea5cc9571534644342458c36d14 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Wed, 8 Nov 2023 17:32:16 -0500 Subject: [PATCH 116/133] build_release: increase timeout again (#30417) * inc timeout * 3 minute timeout --- .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 3efdb8a98b219ee..63d9a7d47d8a761 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -54,7 +54,7 @@ jobs: cd $STRIPPED_DIR ${{ env.RUN }} "CI=1 python selfdrive/manager/build.py" - name: Run tests - timeout-minutes: 2.5 + timeout-minutes: 3 run: | cd $STRIPPED_DIR ${{ env.RUN }} "release/check-dirty.sh && \ From 2eb487c9a5a905b502433db2e7c5e52a52224f39 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Wed, 8 Nov 2023 15:25:41 -0800 Subject: [PATCH 117/133] params: Remove separate CarParams from each daemon (#30405) * remove separate previous route carparams from each daemon and add centrally to controlsd * extract out sigint handler * make process replay work for torqued * don't write param if None --- common/params.cc | 2 +- selfdrive/controls/controlsd.py | 5 ++++ selfdrive/locationd/helpers.py | 27 +++++++++++++++++++ selfdrive/locationd/torqued.py | 22 ++++----------- .../test/process_replay/process_replay.py | 8 +++--- 5 files changed, 43 insertions(+), 21 deletions(-) diff --git a/common/params.cc b/common/params.cc index 3f6cb7044c4d035..9b40773475a2aa2 100644 --- a/common/params.cc +++ b/common/params.cc @@ -99,6 +99,7 @@ std::unordered_map keys = { {"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"CarParamsCache", CLEAR_ON_MANAGER_START}, {"CarParamsPersistent", PERSISTENT}, + {"CarParamsPrevRoute", PERSISTENT}, {"CarVin", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"CompletedTrainingVersion", PERSISTENT}, {"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, @@ -154,7 +155,6 @@ std::unordered_map keys = { {"LastUpdateException", CLEAR_ON_MANAGER_START}, {"LastUpdateTime", PERSISTENT}, {"LiveParameters", PERSISTENT}, - {"LiveTorqueCarParams", PERSISTENT}, {"LiveTorqueParameters", PERSISTENT | DONT_LOG}, {"LongitudinalPersonality", PERSISTENT}, {"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 437cf2d7ce6637b..19ce4079321164d 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -121,6 +121,11 @@ def __init__(self, CI=None): safety_config.safetyModel = car.CarParams.SafetyModel.noOutput self.CP.safetyConfigs = [safety_config] + # Write previous route's CarParams + prev_cp = self.params.get("CarParamsPersistent") + if prev_cp is not None: + self.params.put("CarParamsPrevRoute", prev_cp) + # Write CarParams for radard cp_bytes = self.CP.to_bytes() self.params.put("CarParams", cp_bytes) diff --git a/selfdrive/locationd/helpers.py b/selfdrive/locationd/helpers.py index f41b72c703ed0e5..bde21f78798713e 100644 --- a/selfdrive/locationd/helpers.py +++ b/selfdrive/locationd/helpers.py @@ -1,6 +1,12 @@ import numpy as np +import signal +import sys from typing import List, Optional, Tuple, Any +from cereal import log +from openpilot.common.params import Params +from openpilot.system.swaglog import cloudlog + class NPQueue: def __init__(self, maxlen: int, rowsize: int) -> None: @@ -48,3 +54,24 @@ def get_points(self, num_points: Optional[int] = None) -> Any: def load_points(self, points: List[List[float]]) -> None: for point in points: self.add_point(*point) + + +class ParameterEstimator: + """ Base class for parameter estimators """ + def reset(self) -> None: + raise NotImplementedError + + def handle_log(self, t: int, which: str, msg: log.Event) -> None: + raise NotImplementedError + + def get_msg(self, valid: bool, with_points: bool) -> log.Event: + raise NotImplementedError + + +def cache_points_onexit(param_name, estimator, sig, frame): + signal.signal(sig, signal.SIG_DFL) + cloudlog.warning(f"Caching {param_name} param") + params = Params() + msg = estimator.get_msg(valid=True, with_points=True) + params.put(param_name, msg.to_bytes()) + sys.exit(0) diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index 829f8db417697a8..ff1fac2c22dcc78 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -1,9 +1,9 @@ #!/usr/bin/env python3 import os -import sys import signal import numpy as np from collections import deque, defaultdict +from functools import partial import cereal.messaging as messaging from cereal import car, log @@ -12,7 +12,7 @@ from openpilot.common.filter_simple import FirstOrderFilter from openpilot.system.swaglog import cloudlog from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY -from openpilot.selfdrive.locationd.helpers import PointBuckets +from openpilot.selfdrive.locationd.helpers import PointBuckets, ParameterEstimator, cache_points_onexit HISTORY = 5 # secs POINTS_PER_BUCKET = 1500 @@ -52,7 +52,7 @@ def add_point(self, x, y): break -class TorqueEstimator: +class TorqueEstimator(ParameterEstimator): def __init__(self, CP, decimated=False): self.hist_len = int(HISTORY / DT_MDL) self.lag = CP.steerActuatorDelay + .2 # from controlsd @@ -95,7 +95,7 @@ def __init__(self, CP, decimated=False): # try to restore cached params params = Params() - params_cache = params.get("LiveTorqueCarParams") + params_cache = params.get("CarParamsPrevRoute") torque_cache = params.get("LiveTorqueParameters") if params_cache is not None and torque_cache is not None: try: @@ -116,7 +116,6 @@ def __init__(self, CP, decimated=False): cloudlog.info("restored torque params from cache") except Exception: cloudlog.exception("failed to restore cached torque params") - params.remove("LiveTorqueCarParams") params.remove("LiveTorqueParameters") self.filtered_params = {} @@ -228,19 +227,8 @@ def main(): with car.CarParams.from_bytes(params.get("CarParams", block=True)) as CP: estimator = TorqueEstimator(CP) - def cache_params(sig, frame): - signal.signal(sig, signal.SIG_DFL) - cloudlog.warning("caching torque params") - - params = Params() - params.put("LiveTorqueCarParams", CP.as_builder().to_bytes()) - - msg = estimator.get_msg(with_points=True) - params.put("LiveTorqueParameters", msg.to_bytes()) - - sys.exit(0) if "REPLAY" not in os.environ: - signal.signal(signal.SIGINT, cache_params) + signal.signal(signal.SIGINT, partial(cache_points_onexit, "LiveTorqueParameters", estimator)) while True: sm.update() diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index a520b3d7409e467..a26e9645504d341 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -594,10 +594,13 @@ def get_custom_params_from_lr(lr: LogIterable, initial_state: str = "first") -> assert initial_state in ["first", "last"] msg_index = 0 if initial_state == "first" else -1 - assert len(car_params) > 0, "carParams required for initial state of liveParameters and liveTorqueCarParams" + assert len(car_params) > 0, "carParams required for initial state of liveParameters and CarParamsPrevRoute" CP = car_params[msg_index].carParams - custom_params = {} + custom_params = { + "CarParamsPrevRoute": CP.as_builder().to_bytes() + } + if len(live_calibration) > 0: custom_params["CalibrationParams"] = live_calibration[msg_index].as_builder().to_bytes() if len(live_parameters) > 0: @@ -605,7 +608,6 @@ def get_custom_params_from_lr(lr: LogIterable, initial_state: str = "first") -> lp_dict["carFingerprint"] = CP.carFingerprint custom_params["LiveParameters"] = json.dumps(lp_dict) if len(live_torque_parameters) > 0: - custom_params["LiveTorqueCarParams"] = CP.as_builder().to_bytes() custom_params["LiveTorqueParameters"] = live_torque_parameters[msg_index].as_builder().to_bytes() return custom_params From 53b6ab9e180381134c3809239768477bcc6cbd25 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Wed, 8 Nov 2023 19:04:02 -0500 Subject: [PATCH 118/133] CI: pytest for the rest for GHA (#30418) * pytest car * all pytest * need more time * keep release test short * keep it short --- .github/workflows/selfdrive_tests.yaml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 63d9a7d47d8a761..0bdba6466261d5b 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -26,8 +26,8 @@ env: RUN_CL: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONWARNINGS=error -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $CL_BASE_IMAGE /bin/sh -c - UNIT_TEST: coverage run --append -m unittest discover PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5 --hypothesis-seed 0 + XDIST: -n auto --dist=loadscope jobs: build_release: @@ -58,7 +58,7 @@ jobs: run: | cd $STRIPPED_DIR ${{ env.RUN }} "release/check-dirty.sh && \ - python -m unittest discover selfdrive/car" + MAX_EXAMPLES=5 $PYTEST $XDIST selfdrive/car" - name: pre-commit timeout-minutes: 3 run: | @@ -176,7 +176,7 @@ jobs: - name: Run unit tests timeout-minutes: 15 run: | - ${{ env.RUN }} "$PYTEST -n auto --dist=loadscope --timeout 30 -o cpp_files=test_* -m 'not slow' && \ + ${{ env.RUN }} "$PYTEST $XDIST --timeout 30 -o cpp_files=test_* -m 'not slow' && \ ./selfdrive/ui/tests/create_test_translations.sh && \ QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \ ./selfdrive/ui/tests/test_translations.py && \ @@ -253,7 +253,7 @@ jobs: - name: Run regen timeout-minutes: 30 run: | - ${{ env.RUN_CL }} "ONNXCPU=1 $PYTEST -n auto --dist=loadscope selfdrive/test/process_replay/test_regen.py && \ + ${{ env.RUN_CL }} "ONNXCPU=1 $PYTEST $XDIST selfdrive/test/process_replay/test_regen.py && \ chmod -R 777 /tmp/comma_download_cache" test_modeld: @@ -283,8 +283,7 @@ jobs: timeout-minutes: 4 run: | ${{ env.RUN_CL }} "unset PYTHONWARNINGS && \ - $UNIT_TEST selfdrive/modeld && \ - coverage xml" + $PYTEST selfdrive/modeld" - name: "Upload coverage to Codecov" uses: codecov/codecov-action@v3 @@ -311,7 +310,7 @@ jobs: - name: Test car models timeout-minutes: 25 run: | - ${{ env.RUN }} "$PYTEST -n auto --dist=loadscope selfdrive/car/tests/test_models.py && \ + ${{ env.RUN }} "$PYTEST $XDIST selfdrive/car/tests/test_models.py && \ chmod -R 777 /tmp/comma_download_cache" env: NUM_JOBS: 5 From eed0ddc3b83dd88f0a927f3d5ad04d2260800948 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Wed, 8 Nov 2023 19:30:22 -0500 Subject: [PATCH 119/133] bump panda (#30419) --- panda | 2 +- selfdrive/car/subaru/interface.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/panda b/panda index fa04f476000e8cf..3f25ccabd6c46ba 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit fa04f476000e8cfff72780212b115b5ab059b079 +Subproject commit 3f25ccabd6c46ba06bf32fb15b221c2fcdfc5191 diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index 10ed728812c92a9..79576f6433e5552 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -97,7 +97,7 @@ def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): ret.steerActuatorDelay = 0.1 elif candidate in (CAR.FORESTER_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018): - ret.safetyConfigs[0].safetyParam = 1 # Outback 2018-2019 and Forester have reversed driver torque signal + ret.safetyConfigs[0].safetyParam = Panda.FLAG_SUBARU_PREGLOBAL_REVERSED_DRIVER_TORQUE # Outback 2018-2019 and Forester have reversed driver torque signal ret.mass = 1568 ret.wheelbase = 2.67 ret.centerToFront = ret.wheelbase * 0.5 From f9a5f64498bf4bcb8b5f69629de34266aa6de341 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 9 Nov 2023 10:54:24 -0800 Subject: [PATCH 120/133] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 3f25ccabd6c46ba..d2ea9ad293df232 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 3f25ccabd6c46ba06bf32fb15b221c2fcdfc5191 +Subproject commit d2ea9ad293df232bcd7dc808bb6e577e3d8b483d From 5c2796a104fd2bfb4ef7a541108bd4faee587ba5 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Thu, 9 Nov 2023 14:12:19 -0500 Subject: [PATCH 121/133] CI: label codecov uploads (#30426) * label * matrix --- .github/workflows/selfdrive_tests.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 0bdba6466261d5b..bb5b0a137a843f9 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -184,6 +184,8 @@ jobs: ./selfdrive/test/process_replay/test_fuzzy.py" - name: "Upload coverage to Codecov" uses: codecov/codecov-action@v3 + with: + name: ${{ github.job }} process_replay: name: process replay @@ -228,6 +230,8 @@ jobs: ${{ env.RUN }} "unset PYTHONWARNINGS && CI=1 AZURE_TOKEN='$AZURE_TOKEN' python selfdrive/test/process_replay/test_processes.py -j$(nproc) --upload-only" - name: "Upload coverage to Codecov" uses: codecov/codecov-action@v3 + with: + name: ${{ github.job }} regen: name: regen @@ -286,6 +290,8 @@ jobs: $PYTEST selfdrive/modeld" - name: "Upload coverage to Codecov" uses: codecov/codecov-action@v3 + with: + name: ${{ github.job }} test_cars: name: cars @@ -317,6 +323,8 @@ jobs: JOB_ID: ${{ matrix.job }} - name: "Upload coverage to Codecov" uses: codecov/codecov-action@v3 + with: + name: ${{ github.job }}-${{ matrix.job }} car_docs_diff: name: PR comments From 1e91cf92a180f7093279d19e4a8694c353910d15 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Thu, 9 Nov 2023 18:19:10 -0500 Subject: [PATCH 122/133] CI: codecov for multiprocessing (#30428) * concurrencty codecov * its a list * retrigger ci * increase delay --- .github/workflows/selfdrive_tests.yaml | 2 ++ pyproject.toml | 3 +++ selfdrive/athena/tests/test_athenad.py | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index bb5b0a137a843f9..aba630f67c7fbc4 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -213,6 +213,7 @@ jobs: run: | ${{ env.RUN }} "CI=1 coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \ chmod -R 777 /tmp/comma_download_cache && \ + coverage combine && \ coverage xml" - name: Print diff id: print-diff @@ -282,6 +283,7 @@ jobs: run: | ${{ env.RUN_CL }} "unset PYTHONWARNINGS && \ ONNXCPU=1 CI=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \ + coverage combine && \ coverage xml" - name: Run unit tests timeout-minutes: 4 diff --git a/pyproject.toml b/pyproject.toml index 71b677fbb7fd0b2..16dad2c643a5d0a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -199,3 +199,6 @@ flake8-implicit-str-concat.allow-multiline=false "system".msg = "Use openpilot.system" "third_party".msg = "Use openpilot.third_party" "tools".msg = "Use openpilot.tools" + +[tool.coverage.run] +concurrency = ["multiprocessing", "thread"] \ No newline at end of file diff --git a/selfdrive/athena/tests/test_athenad.py b/selfdrive/athena/tests/test_athenad.py index e81753a6a01a0f5..6d3c5fdb337c778 100755 --- a/selfdrive/athena/tests/test_athenad.py +++ b/selfdrive/athena/tests/test_athenad.py @@ -87,7 +87,7 @@ def send_deviceState(): p = Process(target=send_deviceState) p.start() - time.sleep(0.1) + time.sleep(0.2) try: deviceState = dispatcher["getMessage"]("deviceState") assert deviceState['deviceState'] From 863fdec50e6e222b4b50157c7fe2e254de3435bd Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Thu, 9 Nov 2023 18:52:28 -0500 Subject: [PATCH 123/133] Revert "CI: codecov for multiprocessing" (#30431) Revert "CI: codecov for multiprocessing (#30428)" This reverts commit 1e91cf92a180f7093279d19e4a8694c353910d15. --- .github/workflows/selfdrive_tests.yaml | 2 -- pyproject.toml | 3 --- selfdrive/athena/tests/test_athenad.py | 2 +- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index aba630f67c7fbc4..bb5b0a137a843f9 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -213,7 +213,6 @@ jobs: run: | ${{ env.RUN }} "CI=1 coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \ chmod -R 777 /tmp/comma_download_cache && \ - coverage combine && \ coverage xml" - name: Print diff id: print-diff @@ -283,7 +282,6 @@ jobs: run: | ${{ env.RUN_CL }} "unset PYTHONWARNINGS && \ ONNXCPU=1 CI=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \ - coverage combine && \ coverage xml" - name: Run unit tests timeout-minutes: 4 diff --git a/pyproject.toml b/pyproject.toml index 16dad2c643a5d0a..71b677fbb7fd0b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -199,6 +199,3 @@ flake8-implicit-str-concat.allow-multiline=false "system".msg = "Use openpilot.system" "third_party".msg = "Use openpilot.third_party" "tools".msg = "Use openpilot.tools" - -[tool.coverage.run] -concurrency = ["multiprocessing", "thread"] \ No newline at end of file diff --git a/selfdrive/athena/tests/test_athenad.py b/selfdrive/athena/tests/test_athenad.py index 6d3c5fdb337c778..e81753a6a01a0f5 100755 --- a/selfdrive/athena/tests/test_athenad.py +++ b/selfdrive/athena/tests/test_athenad.py @@ -87,7 +87,7 @@ def send_deviceState(): p = Process(target=send_deviceState) p.start() - time.sleep(0.2) + time.sleep(0.1) try: deviceState = dispatcher["getMessage"]("deviceState") assert deviceState['deviceState'] From bd00fba980f60b8434e428d1ffa5a948cbe83629 Mon Sep 17 00:00:00 2001 From: Eric Brown Date: Thu, 9 Nov 2023 18:11:44 -0700 Subject: [PATCH 124/133] Fix typo in CARS.md (#30433) --- docs/CARS.md | 2 +- selfdrive/car/CARS_template.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index eb7f88d7317423c..3e7d8bbeb801681 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -318,7 +318,7 @@ If your car has the following packages or features, then it's a good candidate f ### FlexRay -All the cars that openpilot supports use a [CAN bus](https://en.wikipedia.org/wiki/CAN_bus) for communication between all the car's computers, however a CAN bus isn't the only way that the cars in your computer can communicate. Most, if not all, vehicles from the following manufacturers use [FlexRay](https://en.wikipedia.org/wiki/FlexRay) instead of a CAN bus: **BMW, Mercedes, Audi, Land Rover, and some Volvo**. These cars may one day be supported, but we have no immediate plans to support FlexRay. +All the cars that openpilot supports use a [CAN bus](https://en.wikipedia.org/wiki/CAN_bus) for communication between all the car's computers, however a CAN bus isn't the only way that the computers in your car can communicate. Most, if not all, vehicles from the following manufacturers use [FlexRay](https://en.wikipedia.org/wiki/FlexRay) instead of a CAN bus: **BMW, Mercedes, Audi, Land Rover, and some Volvo**. These cars may one day be supported, but we have no immediate plans to support FlexRay. ### Toyota Security diff --git a/selfdrive/car/CARS_template.md b/selfdrive/car/CARS_template.md index 9d045e76278f3bb..ab4d231fa7469d4 100644 --- a/selfdrive/car/CARS_template.md +++ b/selfdrive/car/CARS_template.md @@ -53,7 +53,7 @@ If your car has the following packages or features, then it's a good candidate f ### FlexRay -All the cars that openpilot supports use a [CAN bus](https://en.wikipedia.org/wiki/CAN_bus) for communication between all the car's computers, however a CAN bus isn't the only way that the cars in your computer can communicate. Most, if not all, vehicles from the following manufacturers use [FlexRay](https://en.wikipedia.org/wiki/FlexRay) instead of a CAN bus: **BMW, Mercedes, Audi, Land Rover, and some Volvo**. These cars may one day be supported, but we have no immediate plans to support FlexRay. +All the cars that openpilot supports use a [CAN bus](https://en.wikipedia.org/wiki/CAN_bus) for communication between all the car's computers, however a CAN bus isn't the only way that the computers in your car can communicate. Most, if not all, vehicles from the following manufacturers use [FlexRay](https://en.wikipedia.org/wiki/FlexRay) instead of a CAN bus: **BMW, Mercedes, Audi, Land Rover, and some Volvo**. These cars may one day be supported, but we have no immediate plans to support FlexRay. ### Toyota Security From cf2d4fd7ea85034983bb7ce0d3f56e3d79a8949a Mon Sep 17 00:00:00 2001 From: Nickolas Komarnitsky Date: Thu, 9 Nov 2023 18:42:36 -0700 Subject: [PATCH 125/133] Subaru: Add FW for 2022 Legacy (#30434) Update values.py --- selfdrive/car/subaru/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index c9dc6ba5db710d5..882d46b7c340233 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -207,6 +207,7 @@ def init_make(self, CP: car.CarParams): b'\xa1\\ x04\x01', b'\xa1 \x03\x03', b'\xa1 \x02\x01', + b'\xa1 \x02\x02', ], (Ecu.eps, 0x746, None): [ b'\x9b\xc0\x11\x00', @@ -220,11 +221,13 @@ def init_make(self, CP: car.CarParams): b'\xde\"a0\x07', b'\xe2"aq\x07', b'\xde,\xa0@\x07', + b'\xe2,\xa0@\x07', ], (Ecu.transmission, 0x7e1, None): [ b'\xa5\xf6\x05@\x00', b'\xa7\xf6\x04@\x00', b'\xa5\xfe\xc7@\x00', + b'\xa7\xfe\xc4@\x00', ], }, CAR.IMPREZA: { From 26a82e70d547a479c768d1971dca151f34aadcb6 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 10 Nov 2023 10:02:48 +0800 Subject: [PATCH 126/133] replay: make `speed_` atomic (#30429) make speed_ atomic --- tools/replay/replay.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/replay/replay.h b/tools/replay/replay.h index 01969b0a9f44ad6..e26ef883b67b80f 100644 --- a/tools/replay/replay.h +++ b/tools/replay/replay.h @@ -144,7 +144,7 @@ protected slots: std::vector> timeline; std::set allow_list; std::string car_fingerprint_; - float speed_ = 1.0; + std::atomic speed_ = 1.0; replayEventFilter event_filter = nullptr; void *filter_opaque = nullptr; int segment_cache_limit = MIN_SEGMENTS_CACHE; From 515e57402a4ea1c6637b2a377af0dd86214a9373 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 9 Nov 2023 18:09:18 -0800 Subject: [PATCH 127/133] SOM boot recovery (#30427) * SOM boot recovery * bump * master --- common/params.cc | 1 + panda | 2 +- selfdrive/boardd/pandad.py | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/common/params.cc b/common/params.cc index 9b40773475a2aa2..54168165a176ec2 100644 --- a/common/params.cc +++ b/common/params.cc @@ -180,6 +180,7 @@ std::unordered_map keys = { {"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START}, {"OpenpilotEnabledToggle", PERSISTENT}, {"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, + {"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"PandaSignatures", CLEAR_ON_MANAGER_START}, {"Passive", PERSISTENT}, {"PrimeType", PERSISTENT}, diff --git a/panda b/panda index d2ea9ad293df232..a1d699b87d05d4a 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit d2ea9ad293df232bcd7dc808bb6e577e3d8b483d +Subproject commit a1d699b87d05d4ae9d93adc422026864aaedcbdc diff --git a/selfdrive/boardd/pandad.py b/selfdrive/boardd/pandad.py index 433de70d431c84e..14d272965da5647 100755 --- a/selfdrive/boardd/pandad.py +++ b/selfdrive/boardd/pandad.py @@ -144,6 +144,9 @@ def main() -> NoReturn: if health["heartbeat_lost"]: params.put_bool("PandaHeartbeatLost", True) cloudlog.event("heartbeat lost", deviceState=health, serial=panda.get_usb_serial()) + if health["som_reset_triggered"]: + params.put_bool("PandaSomResetTriggered", True) + cloudlog.event("panda.som_reset_triggered", health=health, serial=panda.get_usb_serial()) if first_run: if panda.is_internal(): From db3f56a6f6f3160aa1ff94cf2434f791957049b1 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Thu, 9 Nov 2023 23:18:35 -0500 Subject: [PATCH 128/133] VW MQB: Add FW for 2020 Volkswagen Atlas (#30430) * VW MQB: Add FW for 2020 Volkswagen Atlas * oops --- 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 3e7d8bbeb801681..b7f083b8e82dc59 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -244,7 +244,7 @@ A supported vehicle is one that just works when you install a comma device. All |Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 J533 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 J533 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 J533 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 J533 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 J533 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 J533 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 6439fb0b6bbf959..3c9aeb55d76a067 100644 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -196,7 +196,7 @@ def init_make(self, CP: car.CarParams): ], CAR.ATLAS_MK1: [ VWCarInfo("Volkswagen Atlas 2018-23"), - VWCarInfo("Volkswagen Atlas Cross Sport 2021-22"), + VWCarInfo("Volkswagen Atlas Cross Sport 2020-22"), VWCarInfo("Volkswagen Teramont 2018-22"), VWCarInfo("Volkswagen Teramont Cross Sport 2021-22"), VWCarInfo("Volkswagen Teramont X 2021-22"), @@ -350,6 +350,7 @@ def init_make(self, CP: car.CarParams): CAR.ATLAS_MK1: { (Ecu.engine, 0x7e0, None): [ b'\xf1\x8703H906026AA\xf1\x899970', + b'\xf1\x8703H906026AG\xf1\x899973', b'\xf1\x8703H906026AJ\xf1\x890638', b'\xf1\x8703H906026AJ\xf1\x891017', b'\xf1\x8703H906026AT\xf1\x891922', @@ -375,6 +376,7 @@ def init_make(self, CP: car.CarParams): (Ecu.srs, 0x715, None): [ b'\xf1\x873Q0959655BC\xf1\x890503\xf1\x82\0161914151912001103111122031200', b'\xf1\x873Q0959655BN\xf1\x890713\xf1\x82\0162214152212001105141122052900', + b'\xf1\x873Q0959655DB\xf1\x890720\xf1\x82\x0e1114151112001105111122052900', b'\xf1\x873Q0959655DB\xf1\x890720\xf1\x82\0162214152212001105141122052900', b'\xf1\x873Q0959655DM\xf1\x890732\xf1\x82\x0e1114151112001105161122052J00', b'\xf1\x873Q0959655DM\xf1\x890732\xf1\x82\x0e1115151112001105171122052J00', @@ -382,6 +384,7 @@ def init_make(self, CP: car.CarParams): (Ecu.eps, 0x712, None): [ b'\xf1\x873QF909144B \xf1\x891582\xf1\x82\00571B60924A1', b'\xf1\x873QF909144B \xf1\x891582\xf1\x82\x0571B6G920A1', + b'\xf1\x873QF909144B \xf1\x891582\xf1\x82\x0571B6M921A1', b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820528B6080105', b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820528B6090105', ], From 86efd70fa9e1ec2d125cc713e58c76740bc6eee5 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 10 Nov 2023 12:20:48 +0800 Subject: [PATCH 129/133] cabana: allocate qt objects on the heap instead of stack (#30374) allocate qobject in heap --- tools/cabana/chart/chart.cc | 13 +++++++------ tools/cabana/chart/chart.h | 2 +- tools/cabana/chart/chartswidget.cc | 16 +++++++++------- tools/cabana/chart/chartswidget.h | 4 ++-- tools/cabana/videowidget.cc | 9 +++++---- tools/cabana/videowidget.h | 2 +- 6 files changed, 25 insertions(+), 21 deletions(-) diff --git a/tools/cabana/chart/chart.cc b/tools/cabana/chart/chart.cc index 28d122576cccb53..4cd8eaf8b446dca 100644 --- a/tools/cabana/chart/chart.cc +++ b/tools/cabana/chart/chart.cc @@ -25,7 +25,7 @@ const int AXIS_X_TOP_MARGIN = 4; static inline bool xLessThan(const QPointF &p, float x) { return p.x() < x; } ChartView::ChartView(const std::pair &x_range, ChartsWidget *parent) - : charts_widget(parent), tip_label(this), QChartView(parent) { + : charts_widget(parent), QChartView(parent) { series_type = (SeriesType)settings.chart_series_type; chart()->setBackgroundVisible(false); axis_x = new QValueAxis(this); @@ -38,6 +38,7 @@ ChartView::ChartView(const std::pair &x_range, ChartsWidget *par axis_x->setRange(x_range.first, x_range.second); + tip_label = new TipLabel(this); createToolButtons(); setRubberBand(QChartView::HorizontalRubberBand); setMouseTracking(true); @@ -416,7 +417,7 @@ qreal ChartView::niceNumber(qreal x, bool ceiling) { } void ChartView::leaveEvent(QEvent *event) { - if (tip_label.isVisible()) { + if (tip_label->isVisible()) { charts_widget->showValueTip(-1); } QChartView::leaveEvent(event); @@ -543,7 +544,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { if (!is_zooming && plot_area.contains(ev->pos())) { const double sec = chart()->mapToValue(ev->pos()).x(); charts_widget->showValueTip(sec); - } else if (tip_label.isVisible()) { + } else if (tip_label->isVisible()) { charts_widget->showValueTip(-1); } @@ -563,7 +564,7 @@ void ChartView::showTip(double sec) { QRect tip_area(0, chart()->plotArea().top(), rect().width(), chart()->plotArea().height()); QRect visible_rect = charts_widget->chartVisibleRect(this).intersected(tip_area); if (visible_rect.isEmpty()) { - tip_label.hide(); + tip_label->hide(); return; } @@ -593,14 +594,14 @@ void ChartView::showTip(double sec) { QPoint pt(x, chart()->plotArea().top()); text_list.push_front(QString::number(chart()->mapToValue({x, 0}).x(), 'f', 3)); QString text = "

" % text_list.join("
") % "

"; - tip_label.showText(pt, text, this, visible_rect); + tip_label->showText(pt, text, this, visible_rect); viewport()->update(); } void ChartView::hideTip() { clearTrackPoints(); tooltip_x = -1; - tip_label.hide(); + tip_label->hide(); viewport()->update(); } diff --git a/tools/cabana/chart/chart.h b/tools/cabana/chart/chart.h index 896eaaf2a331cb9..d690a14d1cc1122 100644 --- a/tools/cabana/chart/chart.h +++ b/tools/cabana/chart/chart.h @@ -108,7 +108,7 @@ private slots: QGraphicsPixmapItem *move_icon; QGraphicsProxyWidget *close_btn_proxy; QGraphicsProxyWidget *manage_btn_proxy; - TipLabel tip_label; + TipLabel *tip_label; std::vector sigs; double cur_sec = 0; SeriesType series_type = SeriesType::Line; diff --git a/tools/cabana/chart/chartswidget.cc b/tools/cabana/chart/chartswidget.cc index 0db99063e0be6bc..63d6091cac410e2 100644 --- a/tools/cabana/chart/chartswidget.cc +++ b/tools/cabana/chart/chartswidget.cc @@ -14,7 +14,9 @@ const int MAX_COLUMN_COUNT = 4; const int CHART_SPACING = 4; -ChartsWidget::ChartsWidget(QWidget *parent) : align_timer(this), auto_scroll_timer(this), QFrame(parent) { +ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { + align_timer = new QTimer(this); + auto_scroll_timer = new QTimer(this); setFrameStyle(QFrame::StyledPanel | QFrame::Plain); QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); @@ -95,9 +97,9 @@ ChartsWidget::ChartsWidget(QWidget *parent) : align_timer(this), auto_scroll_tim range_slider->setValue(max_chart_range); updateToolBar(); - align_timer.setSingleShot(true); - QObject::connect(&align_timer, &QTimer::timeout, this, &ChartsWidget::alignCharts); - QObject::connect(&auto_scroll_timer, &QTimer::timeout, this, &ChartsWidget::doAutoScroll); + align_timer->setSingleShot(true); + QObject::connect(align_timer, &QTimer::timeout, this, &ChartsWidget::alignCharts); + QObject::connect(auto_scroll_timer, &QTimer::timeout, this, &ChartsWidget::doAutoScroll); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll); QObject::connect(can, &AbstractStream::eventsMerged, this, &ChartsWidget::eventsMerged); QObject::connect(can, &AbstractStream::msgsReceived, this, &ChartsWidget::updateState); @@ -253,7 +255,7 @@ ChartView *ChartsWidget::createChart() { chart->setFixedHeight(settings.chart_height); chart->setMinimumWidth(CHART_MIN_WIDTH); chart->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - QObject::connect(chart, &ChartView::axisYLabelWidthChanged, &align_timer, qOverload<>(&QTimer::start)); + QObject::connect(chart, &ChartView::axisYLabelWidthChanged, align_timer, qOverload<>(&QTimer::start)); charts.push_front(chart); currentCharts().push_front(chart); updateLayout(true); @@ -334,11 +336,11 @@ void ChartsWidget::updateLayout(bool force) { } void ChartsWidget::startAutoScroll() { - auto_scroll_timer.start(50); + auto_scroll_timer->start(50); } void ChartsWidget::stopAutoScroll() { - auto_scroll_timer.stop(); + auto_scroll_timer->stop(); auto_scroll_count = 0; } diff --git a/tools/cabana/chart/chartswidget.h b/tools/cabana/chart/chartswidget.h index c85cd09963f7fa3..a39b4d73a59bf6f 100644 --- a/tools/cabana/chart/chartswidget.h +++ b/tools/cabana/chart/chartswidget.h @@ -109,8 +109,8 @@ public slots: int column_count = 1; int current_column_count = 0; int auto_scroll_count = 0; - QTimer auto_scroll_timer; - QTimer align_timer; + QTimer *auto_scroll_timer; + QTimer *align_timer; int current_theme = 0; friend class ZoomCommand; friend class ChartView; diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index bbb1ef28daf7960..1ecdc8da1c81468 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -232,7 +232,8 @@ void VideoWidget::updatePlayBtnState() { // Slider -Slider::Slider(QWidget *parent) : thumbnail_label(parent), QSlider(Qt::Horizontal, parent) { +Slider::Slider(QWidget *parent) : QSlider(Qt::Horizontal, parent) { + thumbnail_label = new InfoLabel(parent); setMouseTracking(true); } @@ -321,9 +322,9 @@ void Slider::mouseMoveEvent(QMouseEvent *e) { if (!thumb.isNull()) { int x = std::clamp(pos - thumb.width() / 2, THUMBNAIL_MARGIN, width() - thumb.width() - THUMBNAIL_MARGIN + 1); int y = -thumb.height() - THUMBNAIL_MARGIN; - thumbnail_label.showPixmap(mapToParent(QPoint(x, y)), utils::formatSeconds(seconds), thumb, alertInfo(seconds)); + thumbnail_label->showPixmap(mapToParent(QPoint(x, y)), utils::formatSeconds(seconds), thumb, alertInfo(seconds)); } else { - thumbnail_label.hide(); + thumbnail_label->hide(); } QSlider::mouseMoveEvent(e); } @@ -335,7 +336,7 @@ bool Slider::event(QEvent *event) { case QEvent::FocusIn: case QEvent::FocusOut: case QEvent::Leave: - thumbnail_label.hide(); + thumbnail_label->hide(); break; default: break; diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 69f1edd2bc60728..e163241fb1b7900 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -56,7 +56,7 @@ class Slider : public QSlider { QMap thumbnails; std::map alerts; - InfoLabel thumbnail_label; + InfoLabel *thumbnail_label; }; class VideoWidget : public QFrame { From 72cc2e34cbd3ad25557c4b226c12790cb97457cd Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 9 Nov 2023 20:52:21 -0800 Subject: [PATCH 130/133] camerad: reduce to 1s of buffers --- system/camerad/cameras/camera_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/camerad/cameras/camera_common.h b/system/camerad/cameras/camera_common.h index 3e56f5690d2bf3a..0f69aa37743f111 100644 --- a/system/camerad/cameras/camera_common.h +++ b/system/camerad/cameras/camera_common.h @@ -26,7 +26,7 @@ #define CAMERA_ID_OX03C10 9 #define CAMERA_ID_MAX 10 -const int YUV_BUFFER_COUNT = 40; +const int YUV_BUFFER_COUNT = 20; enum CameraType { RoadCam = 0, From e94c3c556959112fbe0a465289eb5fec7f4ca63a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 10 Nov 2023 01:20:23 -0800 Subject: [PATCH 131/133] Hyundai CAN: update driver braking signal (#30424) * use DriverOverride * bump --- panda | 2 +- selfdrive/car/hyundai/carstate.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/panda b/panda index a1d699b87d05d4a..5e22e87cf649ddb 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit a1d699b87d05d4ae9d93adc422026864aaedcbdc +Subproject commit 5e22e87cf649ddbef7267bfeb1b7b0793b46dc6c diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index bd3ef828f845d07..edc9e4855f62d46 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -115,7 +115,7 @@ def update(self, cp, cp_cam): # TODO: Find brake pressure ret.brake = 0 - ret.brakePressed = cp.vl["TCS13"]["DriverBraking"] != 0 + ret.brakePressed = cp.vl["TCS13"]["DriverOverride"] == 2 # 2 includes regen braking by user on HEV/EV 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 From 26294173207cd5e3c586ca71a88fdd3a09fc7345 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Fri, 10 Nov 2023 10:02:05 -0800 Subject: [PATCH 132/133] CI: codecov for multiprocessing (#30432) --- .github/workflows/selfdrive_tests.yaml | 2 ++ pyproject.toml | 3 +++ selfdrive/athena/tests/test_athenad.py | 17 +++++++++-------- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index bb5b0a137a843f9..aba630f67c7fbc4 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -213,6 +213,7 @@ jobs: run: | ${{ env.RUN }} "CI=1 coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \ chmod -R 777 /tmp/comma_download_cache && \ + coverage combine && \ coverage xml" - name: Print diff id: print-diff @@ -282,6 +283,7 @@ jobs: run: | ${{ env.RUN_CL }} "unset PYTHONWARNINGS && \ ONNXCPU=1 CI=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \ + coverage combine && \ coverage xml" - name: Run unit tests timeout-minutes: 4 diff --git a/pyproject.toml b/pyproject.toml index 71b677fbb7fd0b2..16dad2c643a5d0a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -199,3 +199,6 @@ flake8-implicit-str-concat.allow-multiline=false "system".msg = "Use openpilot.system" "third_party".msg = "Use openpilot.third_party" "tools".msg = "Use openpilot.tools" + +[tool.coverage.run] +concurrency = ["multiprocessing", "thread"] \ No newline at end of file diff --git a/selfdrive/athena/tests/test_athenad.py b/selfdrive/athena/tests/test_athenad.py index e81753a6a01a0f5..8829ebfbf12776e 100755 --- a/selfdrive/athena/tests/test_athenad.py +++ b/selfdrive/athena/tests/test_athenad.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import json +import multiprocessing import os import requests import shutil @@ -12,7 +13,6 @@ from parameterized import parameterized from typing import Optional -from multiprocessing import Process from pympler.tracker import SummaryTracker from unittest import mock from websocket import ABNF @@ -75,24 +75,25 @@ def test_getMessage(self): with self.assertRaises(TimeoutError) as _: dispatcher["getMessage"]("controlsState") - def send_deviceState(): - messaging.context = messaging.Context() - pub_sock = messaging.pub_sock("deviceState") - start = time.time() + end_event = multiprocessing.Event() + + pub_sock = messaging.pub_sock("deviceState") - while time.time() - start < 1: + def send_deviceState(): + while not end_event.is_set(): msg = messaging.new_message('deviceState') pub_sock.send(msg.to_bytes()) time.sleep(0.01) - p = Process(target=send_deviceState) + p = multiprocessing.Process(target=send_deviceState) p.start() time.sleep(0.1) try: deviceState = dispatcher["getMessage"]("deviceState") assert deviceState['deviceState'] finally: - p.terminate() + end_event.set() + p.join() def test_listDataDirectory(self): route = '2021-03-29--13-32-47' From 5f7143df02b857201e2615240ccd1be06daa32fe Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 10 Nov 2023 16:55:25 -0800 Subject: [PATCH 133/133] jenkins: use build.py to manage cache size (#30440) * jenkins: use build.py to manage cache size * label * set pp * double * cleanup * non mimimal build on PC --------- Co-authored-by: Justin Newberry --- Jenkinsfile | 4 ++-- selfdrive/manager/build.py | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 314170341ecbf4e..6857ce36e18605e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -85,7 +85,7 @@ def pcStage(String stageName, Closure body) { checkout scm - def dockerArgs = '--user=batman -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/scons_cache:/tmp/scons_cache'; + def dockerArgs = "--user=batman -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/scons_cache:/tmp/scons_cache -e PYTHONPATH=${env.WORKSPACE}"; docker.build("openpilot-base:build-${env.GIT_COMMIT}", "-f Dockerfile.openpilot_base .").inside(dockerArgs) { timeout(time: 20, unit: 'MINUTES') { try { @@ -228,7 +228,7 @@ node { }, 'car tests': { pcStage("car tests") { - sh "scons -j30" + sh label: "build", script: "selfdrive/manager/build.py" sh label: "test_models.py", script: "INTERNAL_SEG_CNT=250 INTERNAL_SEG_LIST=selfdrive/car/tests/test_models_segs.txt FILEREADER_CACHE=1 \ pytest -n42 --dist=loadscope selfdrive/car/tests/test_models.py" sh label: "test_car_interfaces.py", script: "MAX_EXAMPLES=100 pytest -n42 selfdrive/car/tests/test_car_interfaces.py" diff --git a/selfdrive/manager/build.py b/selfdrive/manager/build.py index be37b3e7e4795ea..247f3c8fb8cc829 100755 --- a/selfdrive/manager/build.py +++ b/selfdrive/manager/build.py @@ -19,19 +19,21 @@ MAX_BUILD_PROGRESS = 100 PREBUILT = os.path.exists(os.path.join(BASEDIR, 'prebuilt')) -def build(spinner: Spinner, dirty: bool = False) -> None: +def build(spinner: Spinner, dirty: bool = False, minimal: bool = False) -> None: env = os.environ.copy() env['SCONS_PROGRESS'] = "1" nproc = os.cpu_count() if nproc is None: nproc = 2 + extra_args = ["--minimal"] if minimal else [] + # building with all cores can result in using too # much memory, so retry with less parallelism compile_output: List[bytes] = [] for n in (nproc, nproc/2, 1): compile_output.clear() - scons: subprocess.Popen = subprocess.Popen(["scons", f"-j{int(n)}", "--cache-populate", "--minimal"], cwd=BASEDIR, env=env, stderr=subprocess.PIPE) + scons: subprocess.Popen = subprocess.Popen(["scons", f"-j{int(n)}", "--cache-populate", *extra_args], cwd=BASEDIR, env=env, stderr=subprocess.PIPE) assert scons.stderr is not None # Read progress from stderr and update spinner @@ -86,4 +88,4 @@ def build(spinner: Spinner, dirty: bool = False) -> None: if __name__ == "__main__" and not PREBUILT: spinner = Spinner() spinner.update_progress(0, 100) - build(spinner, is_dirty()) + build(spinner, is_dirty(), minimal = AGNOS)