From 12073c07afbd0de42ed475c9368ad9f51fd0c631 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 27 Aug 2023 22:13:43 +0800 Subject: [PATCH 01/13] ui/MapSettings: sort destinations by recent activity (#29079) --- common/params.cc | 1 + selfdrive/ui/qt/maps/map_settings.cc | 138 +++++++++++++++++---------- selfdrive/ui/qt/maps/map_settings.h | 22 ++--- 3 files changed, 98 insertions(+), 63 deletions(-) diff --git a/common/params.cc b/common/params.cc index e8ab42c0b0..63baa30315 100644 --- a/common/params.cc +++ b/common/params.cc @@ -158,6 +158,7 @@ std::unordered_map keys = { {"LongitudinalPersonality", PERSISTENT}, {"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"NavDestinationWaypoints", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, + {"NavPastDestinations", PERSISTENT}, {"NavSettingLeftSide", PERSISTENT}, {"NavSettingTime24h", PERSISTENT}, {"NavdRender", PERSISTENT}, diff --git a/selfdrive/ui/qt/maps/map_settings.cc b/selfdrive/ui/qt/maps/map_settings.cc index a4386ded72..52756abdc3 100644 --- a/selfdrive/ui/qt/maps/map_settings.cc +++ b/selfdrive/ui/qt/maps/map_settings.cc @@ -9,6 +9,12 @@ #include "selfdrive/ui/qt/request_repeater.h" #include "selfdrive/ui/qt/widgets/scrollview.h" +static void swap(QJsonValueRef v1, QJsonValueRef v2) { std::swap(v1, v2); } + +static bool locationEqual(const QJsonValue &v1, const QJsonValue &v2) { + return v1["latitude"] == v2["latitude"] && v1["longitude"] == v2["longitude"]; +} + MapSettings::MapSettings(bool closeable, QWidget *parent) : QFrame(parent) { setContentsMargins(0, 0, 0, 0); setAttribute(Qt::WA_NoMousePropagation); @@ -61,11 +67,8 @@ MapSettings::MapSettings(bool closeable, QWidget *parent) : QFrame(parent) { frame->addSpacing(32); current_widget = new DestinationWidget(this); - QObject::connect(current_widget, &DestinationWidget::actionClicked, [=]() { - if (current_destination.empty()) return; - params.remove("NavDestination"); - updateCurrentRoute(); - }); + QObject::connect(current_widget, &DestinationWidget::actionClicked, + []() { NavManager::instance()->setCurrentDestination({}); }); frame->addWidget(current_widget); frame->addSpacing(32); @@ -84,40 +87,16 @@ MapSettings::MapSettings(bool closeable, QWidget *parent) : QFrame(parent) { frame->addWidget(destinations_scroller); setStyleSheet("MapSettings { background-color: #333333; }"); - - QObject::connect(NavigationRequest::instance(), &NavigationRequest::locationsUpdated, this, &MapSettings::updateLocations); - QObject::connect(NavigationRequest::instance(), &NavigationRequest::nextDestinationUpdated, this, &MapSettings::updateCurrentRoute); - - current_locations = NavigationRequest::instance()->currentLocations(); + QObject::connect(NavManager::instance(), &NavManager::updated, this, &MapSettings::refresh); } void MapSettings::showEvent(QShowEvent *event) { - updateCurrentRoute(); -} - -void MapSettings::updateCurrentRoute() { - auto dest = QString::fromStdString(params.get("NavDestination")); - if (dest.size()) { - QJsonDocument doc = QJsonDocument::fromJson(dest.trimmed().toUtf8()); - if (doc.isNull()) { - qWarning() << "JSON Parse failed on NavDestination" << dest; - return; - } - current_destination = doc.object(); - current_widget->set(current_destination, true); - } else { - current_destination = {}; - current_widget->unset("", true); - } - if (isVisible()) refresh(); -} - -void MapSettings::updateLocations(const QJsonArray &locations) { - current_locations = locations; refresh(); } void MapSettings::refresh() { + if (!isVisible()) return; + setUpdatesEnabled(false); auto get_w = [this](int i) { @@ -129,11 +108,17 @@ void MapSettings::refresh() { return w; }; + const auto current_dest = NavManager::instance()->currentDestination(); + if (!current_dest.isEmpty()) { + current_widget->set(current_dest, true); + } else { + current_widget->unset("", true); + } home_widget->unset(NAV_FAVORITE_LABEL_HOME); work_widget->unset(NAV_FAVORITE_LABEL_WORK); int n = 0; - for (auto location : current_locations) { + for (auto location : NavManager::instance()->currentLocations()) { DestinationWidget *w = nullptr; auto dest = location.toObject(); if (dest["save_type"].toString() == NAV_TYPE_FAVORITE) { @@ -143,7 +128,7 @@ void MapSettings::refresh() { } w = w ? w : get_w(n++); w->set(dest, false); - w->setVisible(dest != current_destination); + w->setVisible(!locationEqual(dest, current_dest)); } for (; n < widgets.size(); ++n) widgets[n]->setVisible(false); @@ -151,9 +136,7 @@ void MapSettings::refresh() { } void MapSettings::navigateTo(const QJsonObject &place) { - QJsonDocument doc(place); - params.put("NavDestination", doc.toJson().toStdString()); - updateCurrentRoute(); + NavManager::instance()->setCurrentDestination(place); emit closeSettings(); } @@ -279,24 +262,26 @@ void DestinationWidget::unset(const QString &label, bool current) { setVisible(true); } -// singleton NavigationRequest +// singleton NavManager -NavigationRequest *NavigationRequest::instance() { - static NavigationRequest *request = new NavigationRequest(qApp); +NavManager *NavManager::instance() { + static NavManager *request = new NavManager(qApp); return request; } -NavigationRequest::NavigationRequest(QObject *parent) : QObject(parent) { +NavManager::NavManager(QObject *parent) : QObject(parent) { + locations = QJsonDocument::fromJson(params.get("NavPastDestinations").c_str()).array(); + current_dest = QJsonDocument::fromJson(params.get("NavDestination").c_str()).object(); if (auto dongle_id = getDongleId()) { { // Fetch favorite and recent locations QString url = CommaApi::BASE_URL + "/v1/navigation/" + *dongle_id + "/locations"; RequestRepeater *repeater = new RequestRepeater(this, url, "ApiCache_NavDestinations", 30, true); - QObject::connect(repeater, &RequestRepeater::requestDone, this, &NavigationRequest::parseLocationsResponse); + QObject::connect(repeater, &RequestRepeater::requestDone, this, &NavManager::parseLocationsResponse); } { auto param_watcher = new ParamWatcher(this); - QObject::connect(param_watcher, &ParamWatcher::paramChanged, this, &NavigationRequest::nextDestinationUpdated); + QObject::connect(param_watcher, &ParamWatcher::paramChanged, this, &NavManager::updated); // Destination set while offline QString url = CommaApi::BASE_URL + "/v1/navigation/" + *dongle_id + "/next"; @@ -316,14 +301,14 @@ NavigationRequest::NavigationRequest(QObject *parent) : QObject(parent) { // athena can set destination at any time param_watcher->addParam("NavDestination"); + current_dest = QJsonDocument::fromJson(params.get("NavDestination").c_str()).object(); + emit updated(); }); } } } -static void swap(QJsonValueRef v1, QJsonValueRef v2) { std::swap(v1, v2); } - -void NavigationRequest::parseLocationsResponse(const QString &response, bool success) { +void NavManager::parseLocationsResponse(const QString &response, bool success) { if (!success || response == prev_response) return; prev_response = response; @@ -333,13 +318,62 @@ void NavigationRequest::parseLocationsResponse(const QString &response, bool suc return; } - // Sort: alphabetical FAVORITES, and then most recent (as returned by API). + // set last activity time. + auto remote_locations = doc.array(); + for (QJsonValueRef loc : remote_locations) { + auto obj = loc.toObject(); + obj.insert("time", getLastActivity(obj)); + loc = obj; + } + + locations = remote_locations; + sortLocations(); + emit updated(); +} + +void NavManager::sortLocations() { + // Sort: alphabetical FAVORITES, and then most recent. // We don't need to care about the ordering of HOME and WORK. DestinationWidget always displays them at the top. - locations = doc.array(); std::stable_sort(locations.begin(), locations.end(), [](const QJsonValue &a, const QJsonValue &b) { - bool has_favorite = a["save_type"] == NAV_TYPE_FAVORITE || b["save_type"] == NAV_TYPE_FAVORITE; - return has_favorite && (std::tuple(a["save_type"].toString(), a["place_name"].toString()) < - std::tuple(b["save_type"].toString(), b["place_name"].toString())); + if (a["save_type"] == NAV_TYPE_FAVORITE || b["save_type"] == NAV_TYPE_FAVORITE) { + return (std::tuple(a["save_type"].toString(), a["place_name"].toString()) < + std::tuple(b["save_type"].toString(), b["place_name"].toString())); + } else { + return a["time"].toVariant().toLongLong() > b["time"].toVariant().toLongLong(); + } + }); + + write_param_future = std::async(std::launch::async, [destinations = QJsonArray(locations)]() { + Params().put("NavPastDestinations", QJsonDocument(destinations).toJson().toStdString()); }); - emit locationsUpdated(locations); +} + +qint64 NavManager::getLastActivity(const QJsonObject &loc) const { + qint64 last_activity = 0; + auto it = std::find_if(locations.begin(), locations.end(), + [&loc](const QJsonValue &l) { return locationEqual(loc, l); }); + if (it != locations.end()) { + auto tm = it->toObject().value("time"); + if (!tm.isUndefined() && !tm.isNull()) { + last_activity = tm.toVariant().toLongLong(); + } + } + return last_activity; +} + +void NavManager::setCurrentDestination(const QJsonObject &loc) { + current_dest = loc; + if (!current_dest.isEmpty()) { + current_dest["time"] = QDateTime::currentSecsSinceEpoch(); + auto it = std::find_if(locations.begin(), locations.end(), + [&loc](const QJsonValue &l) { return locationEqual(loc, l); }); + if (it != locations.end()) { + *it = current_dest; + sortLocations(); + } + params.put("NavDestination", QJsonDocument(current_dest).toJson().toStdString()); + } else { + params.remove("NavDestination"); + } + emit updated(); } diff --git a/selfdrive/ui/qt/maps/map_settings.h b/selfdrive/ui/qt/maps/map_settings.h index bee0061932..0e151df4ad 100644 --- a/selfdrive/ui/qt/maps/map_settings.h +++ b/selfdrive/ui/qt/maps/map_settings.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -22,42 +23,41 @@ const QString NAV_FAVORITE_LABEL_WORK = "work"; class DestinationWidget; -class NavigationRequest : public QObject { +class NavManager : public QObject { Q_OBJECT public: - static NavigationRequest *instance(); + static NavManager *instance(); QJsonArray currentLocations() const { return locations; } + QJsonObject currentDestination() const { return current_dest; } + void setCurrentDestination(const QJsonObject &loc); + qint64 getLastActivity(const QJsonObject &loc) const; signals: - void locationsUpdated(const QJsonArray &locations); - void nextDestinationUpdated(); + void updated(); private: - NavigationRequest(QObject *parent); + NavManager(QObject *parent); void parseLocationsResponse(const QString &response, bool success); + void sortLocations(); Params params; QString prev_response; QJsonArray locations; + QJsonObject current_dest; + std::future write_param_future; }; class MapSettings : public QFrame { Q_OBJECT public: explicit MapSettings(bool closeable = false, QWidget *parent = nullptr); - void navigateTo(const QJsonObject &place); - void updateLocations(const QJsonArray &locations); - void updateCurrentRoute(); private: void showEvent(QShowEvent *event) override; void refresh(); - Params params; - QJsonArray current_locations; - QJsonObject current_destination; QVBoxLayout *destinations_layout; DestinationWidget *current_widget; DestinationWidget *home_widget; From 3d1a6f61463f022462c93a331add64af1cb48e94 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Sun, 27 Aug 2023 16:18:42 +0100 Subject: [PATCH 02/13] ui/NavManager: parse location timestamp from API (#29665) --- selfdrive/ui/qt/maps/map_settings.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/selfdrive/ui/qt/maps/map_settings.cc b/selfdrive/ui/qt/maps/map_settings.cc index 52756abdc3..4d655be36c 100644 --- a/selfdrive/ui/qt/maps/map_settings.cc +++ b/selfdrive/ui/qt/maps/map_settings.cc @@ -15,6 +15,11 @@ static bool locationEqual(const QJsonValue &v1, const QJsonValue &v2) { return v1["latitude"] == v2["latitude"] && v1["longitude"] == v2["longitude"]; } +static qint64 convertTimestampToEpoch(const QString ×tamp) { + QDateTime dt = QDateTime::fromString(timestamp, Qt::ISODate); + return dt.isValid() ? dt.toSecsSinceEpoch() : 0; +} + MapSettings::MapSettings(bool closeable, QWidget *parent) : QFrame(parent) { setContentsMargins(0, 0, 0, 0); setAttribute(Qt::WA_NoMousePropagation); @@ -322,7 +327,8 @@ void NavManager::parseLocationsResponse(const QString &response, bool success) { auto remote_locations = doc.array(); for (QJsonValueRef loc : remote_locations) { auto obj = loc.toObject(); - obj.insert("time", getLastActivity(obj)); + auto serverTime = convertTimestampToEpoch(obj["modified"].toString()); + obj.insert("time", qMax(serverTime, getLastActivity(obj))); loc = obj; } From ab05bff07ded3d3cd932c59beaaa75c698195692 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Sun, 27 Aug 2023 09:45:16 -0700 Subject: [PATCH 03/13] CI: fix proc replay download cache permissions (#29636) chmod that --- .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 78b957a468..5c5f8d78d7 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -301,6 +301,7 @@ jobs: timeout-minutes: 30 run: | ${{ env.RUN }} "CI=1 coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \ + chmod -R 777 /tmp/comma_download_cache && \ coverage xml" - name: Print diff id: print-diff From 4f915f4f1a2ed4c62069e03b176d2a4906479c51 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 28 Aug 2023 00:56:49 +0800 Subject: [PATCH 04/13] cabana/MessageListModel: replace `match |=` with `match = match ||` (#29667) --- tools/cabana/messageswidget.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 4e9e0173d7..6a3d11cda1 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -281,7 +281,8 @@ bool MessageListModel::matchMessage(const MessageId &id, const CanData &data, co case Column::NAME: { const auto msg = dbc()->msg(id); match = re.match(msg ? msg->name : UNTITLED).hasMatch(); - match |= msg && std::any_of(msg->sigs.cbegin(), msg->sigs.cend(), [&re](const auto &s) { return re.match(s->name).hasMatch(); }); + match = match || (msg && std::any_of(msg->sigs.cbegin(), msg->sigs.cend(), + [&re](const auto &s) { return re.match(s->name).hasMatch(); })); break; } case Column::SOURCE: @@ -289,7 +290,7 @@ bool MessageListModel::matchMessage(const MessageId &id, const CanData &data, co break; case Column::ADDRESS: { match = re.match(QString::number(id.address, 16)).hasMatch(); - match |= parseRange(txt, id.address, 16); + match = match || parseRange(txt, id.address, 16); break; } case Column::FREQ: @@ -301,8 +302,8 @@ bool MessageListModel::matchMessage(const MessageId &id, const CanData &data, co break; case Column::DATA: { match = QString(data.dat.toHex()).contains(txt, Qt::CaseInsensitive); - match |= re.match(QString(data.dat.toHex())).hasMatch(); - match |= re.match(QString(data.dat.toHex(' '))).hasMatch(); + match = match || re.match(QString(data.dat.toHex())).hasMatch(); + match = match || re.match(QString(data.dat.toHex(' '))).hasMatch(); break; } } From 3a46a853cb22efe0053cf7e99fc7c8e7e676a455 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 28 Aug 2023 01:57:31 +0800 Subject: [PATCH 05/13] ui/driverview: use common SubMaster (#29660) --- selfdrive/ui/qt/offroad/driverview.cc | 4 ++-- selfdrive/ui/qt/offroad/driverview.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/selfdrive/ui/qt/offroad/driverview.cc b/selfdrive/ui/qt/offroad/driverview.cc index ec4b567ca6..693a0253b4 100644 --- a/selfdrive/ui/qt/offroad/driverview.cc +++ b/selfdrive/ui/qt/offroad/driverview.cc @@ -35,7 +35,7 @@ void DriverViewWindow::mouseReleaseEvent(QMouseEvent* e) { closeView(); } -DriverViewScene::DriverViewScene(QWidget* parent) : sm({"driverStateV2"}), QWidget(parent) { +DriverViewScene::DriverViewScene(QWidget* parent) : QWidget(parent) { face_img = loadPixmap("../assets/img_driver_face_static.png", {FACE_IMG_SIZE, FACE_IMG_SIZE}); } @@ -51,7 +51,6 @@ void DriverViewScene::hideEvent(QHideEvent* event) { void DriverViewScene::frameUpdated() { frame_updated = true; - sm.update(0); update(); } @@ -67,6 +66,7 @@ void DriverViewScene::paintEvent(QPaintEvent* event) { return; } + const auto &sm = *(uiState()->sm); cereal::DriverStateV2::Reader driver_state = sm["driverStateV2"].getDriverStateV2(); cereal::DriverStateV2::DriverData::Reader driver_data; diff --git a/selfdrive/ui/qt/offroad/driverview.h b/selfdrive/ui/qt/offroad/driverview.h index a6ea2cbee7..8bfc7a4b7b 100644 --- a/selfdrive/ui/qt/offroad/driverview.h +++ b/selfdrive/ui/qt/offroad/driverview.h @@ -20,7 +20,6 @@ protected: private: Params params; - SubMaster sm; QPixmap face_img; bool is_rhd = false; bool frame_updated = false; From 7f4b588495c2432b0d726fb87e8252a1d58253f8 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Sun, 27 Aug 2023 13:58:18 -0400 Subject: [PATCH 06/13] Docs: Hyundai R Harness (#29662) --- selfdrive/car/docs_definitions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index 3319ba31c8..58545b886c 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -110,6 +110,7 @@ class CarHarness(EnumBase): hyundai_o = BaseCarHarness("Hyundai O connector") hyundai_p = BaseCarHarness("Hyundai P connector") hyundai_q = BaseCarHarness("Hyundai Q connector") + 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") From 4005b6addeda8d58b32f7aa7f96264ef7072887e Mon Sep 17 00:00:00 2001 From: vanillagorillaa <31773928+vanillagorillaa@users.noreply.github.com> Date: Sun, 27 Aug 2023 15:21:06 -0700 Subject: [PATCH 07/13] Docs: Toyota B harness connector (#29669) --- selfdrive/car/docs_definitions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index 58545b886c..71353efac9 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -85,6 +85,7 @@ class CarHarness(EnumBase): bosch_a = BaseCarHarness("Honda Bosch A connector") bosch_b = BaseCarHarness("Honda Bosch B connector") toyota_a = BaseCarHarness("Toyota A connector") + toyota_b = BaseCarHarness("Toyota B connector") subaru_a = BaseCarHarness("Subaru A connector") subaru_b = BaseCarHarness("Subaru B connector") subaru_c = BaseCarHarness("Subaru C connector") From 125bd2cd9ef930f23c8d435ccf2a76b91228abe8 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 28 Aug 2023 06:23:19 +0800 Subject: [PATCH 08/13] ui/network: move to selfdrive/ui/qt/network/ (#29656) * move to ui/qt/network * wifimanager->wifi_manager --- release/files_common | 2 ++ selfdrive/ui/SConscript | 2 +- selfdrive/ui/qt/{offroad => network}/networking.cc | 2 +- selfdrive/ui/qt/{offroad => network}/networking.h | 2 +- selfdrive/ui/qt/{offroad => network}/networkmanager.h | 0 .../ui/qt/{offroad/wifiManager.cc => network/wifi_manager.cc} | 2 +- .../ui/qt/{offroad/wifiManager.h => network/wifi_manager.h} | 2 +- selfdrive/ui/qt/offroad/settings.cc | 2 +- selfdrive/ui/qt/setup/setup.cc | 2 +- selfdrive/ui/qt/setup/updater.cc | 2 +- 10 files changed, 10 insertions(+), 8 deletions(-) rename selfdrive/ui/qt/{offroad => network}/networking.cc (99%) rename selfdrive/ui/qt/{offroad => network}/networking.h (97%) rename selfdrive/ui/qt/{offroad => network}/networkmanager.h (100%) rename selfdrive/ui/qt/{offroad/wifiManager.cc => network/wifi_manager.cc} (99%) rename selfdrive/ui/qt/{offroad/wifiManager.h => network/wifi_manager.h} (98%) diff --git a/release/files_common b/release/files_common index b375c18dce..54aece8530 100644 --- a/release/files_common +++ b/release/files_common @@ -318,6 +318,8 @@ selfdrive/ui/tests/test_translations.py selfdrive/ui/qt/*.cc selfdrive/ui/qt/*.h +selfdrive/ui/qt/network/*.cc +selfdrive/ui/qt/network/*.h selfdrive/ui/qt/offroad/*.cc selfdrive/ui/qt/offroad/*.h selfdrive/ui/qt/offroad/*.qml diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 796f85f1e7..017ce66793 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -24,7 +24,7 @@ widgets_src = ["ui.cc", "qt/widgets/input.cc", "qt/widgets/drive_stats.cc", "qt/ "qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc", "qt/widgets/offroad_alerts.cc", "qt/widgets/prime.cc", "qt/widgets/keyboard.cc", "qt/widgets/scrollview.cc", "qt/widgets/cameraview.cc", "#third_party/qrcode/QrCode.cc", - "qt/request_repeater.cc", "qt/qt_window.cc", "qt/offroad/networking.cc", "qt/offroad/wifiManager.cc"] + "qt/request_repeater.cc", "qt/qt_window.cc", "qt/network/networking.cc", "qt/network/wifi_manager.cc"] qt_env['CPPDEFINES'] = [] if maps: diff --git a/selfdrive/ui/qt/offroad/networking.cc b/selfdrive/ui/qt/network/networking.cc similarity index 99% rename from selfdrive/ui/qt/offroad/networking.cc rename to selfdrive/ui/qt/network/networking.cc index 420bc5a2cf..98ecc90fe3 100644 --- a/selfdrive/ui/qt/offroad/networking.cc +++ b/selfdrive/ui/qt/network/networking.cc @@ -1,4 +1,4 @@ -#include "selfdrive/ui/qt/offroad/networking.h" +#include "selfdrive/ui/qt/network/networking.h" #include diff --git a/selfdrive/ui/qt/offroad/networking.h b/selfdrive/ui/qt/network/networking.h similarity index 97% rename from selfdrive/ui/qt/offroad/networking.h rename to selfdrive/ui/qt/network/networking.h index 81ffb3cf2d..4ff7380f42 100644 --- a/selfdrive/ui/qt/offroad/networking.h +++ b/selfdrive/ui/qt/network/networking.h @@ -2,7 +2,7 @@ #include -#include "selfdrive/ui/qt/offroad/wifiManager.h" +#include "selfdrive/ui/qt/network/wifi_manager.h" #include "selfdrive/ui/qt/widgets/input.h" #include "selfdrive/ui/qt/widgets/ssh_keys.h" #include "selfdrive/ui/qt/widgets/toggle.h" diff --git a/selfdrive/ui/qt/offroad/networkmanager.h b/selfdrive/ui/qt/network/networkmanager.h similarity index 100% rename from selfdrive/ui/qt/offroad/networkmanager.h rename to selfdrive/ui/qt/network/networkmanager.h diff --git a/selfdrive/ui/qt/offroad/wifiManager.cc b/selfdrive/ui/qt/network/wifi_manager.cc similarity index 99% rename from selfdrive/ui/qt/offroad/wifiManager.cc rename to selfdrive/ui/qt/network/wifi_manager.cc index 858de15bfe..03c6896f7a 100644 --- a/selfdrive/ui/qt/offroad/wifiManager.cc +++ b/selfdrive/ui/qt/network/wifi_manager.cc @@ -1,4 +1,4 @@ -#include "selfdrive/ui/qt/offroad/wifiManager.h" +#include "selfdrive/ui/qt/network/wifi_manager.h" #include "selfdrive/ui/ui.h" #include "selfdrive/ui/qt/widgets/prime.h" diff --git a/selfdrive/ui/qt/offroad/wifiManager.h b/selfdrive/ui/qt/network/wifi_manager.h similarity index 98% rename from selfdrive/ui/qt/offroad/wifiManager.h rename to selfdrive/ui/qt/network/wifi_manager.h index c444b2abc1..7debffa452 100644 --- a/selfdrive/ui/qt/offroad/wifiManager.h +++ b/selfdrive/ui/qt/network/wifi_manager.h @@ -4,7 +4,7 @@ #include #include -#include "selfdrive/ui/qt/offroad/networkmanager.h" +#include "selfdrive/ui/qt/network/networkmanager.h" enum class SecurityType { OPEN, diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 8b0f9c1f36..0af027ca90 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -8,7 +8,7 @@ #include -#include "selfdrive/ui/qt/offroad/networking.h" +#include "selfdrive/ui/qt/network/networking.h" #include "common/params.h" #include "common/watchdog.h" diff --git a/selfdrive/ui/qt/setup/setup.cc b/selfdrive/ui/qt/setup/setup.cc index 269874f115..3b3666b19a 100644 --- a/selfdrive/ui/qt/setup/setup.cc +++ b/selfdrive/ui/qt/setup/setup.cc @@ -15,7 +15,7 @@ #include "system/hardware/hw.h" #include "selfdrive/ui/qt/api.h" #include "selfdrive/ui/qt/qt_window.h" -#include "selfdrive/ui/qt/offroad/networking.h" +#include "selfdrive/ui/qt/network/networking.h" #include "selfdrive/ui/qt/util.h" #include "selfdrive/ui/qt/widgets/input.h" diff --git a/selfdrive/ui/qt/setup/updater.cc b/selfdrive/ui/qt/setup/updater.cc index ae5f26c77e..ed47590aa3 100644 --- a/selfdrive/ui/qt/setup/updater.cc +++ b/selfdrive/ui/qt/setup/updater.cc @@ -6,7 +6,7 @@ #include "selfdrive/ui/qt/util.h" #include "selfdrive/ui/qt/qt_window.h" #include "selfdrive/ui/qt/setup/updater.h" -#include "selfdrive/ui/qt/offroad/networking.h" +#include "selfdrive/ui/qt/network/networking.h" Updater::Updater(const QString &updater_path, const QString &manifest_path, QWidget *parent) : updater(updater_path), manifest(manifest_path), QStackedWidget(parent) { From 5716dfc9b54f9f24e412ae020ac572ccec6ae1c9 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Sun, 27 Aug 2023 19:52:38 -0700 Subject: [PATCH 09/13] CI: fix sim/docs scons cache invalidation (#29639) * fix sim and docs images * fix that * that's a weird issue * exists should work fine * as little diff as possible --- docs/docker/Dockerfile | 8 +++---- tools/sim/Dockerfile.sim | 45 +++++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/docs/docker/Dockerfile b/docs/docker/Dockerfile index e079fe6223..240f828912 100644 --- a/docs/docker/Dockerfile +++ b/docs/docker/Dockerfile @@ -2,7 +2,7 @@ FROM ghcr.io/commaai/openpilot-base:latest ENV PYTHONUNBUFFERED 1 -ENV OPENPILOT_PATH /home/batman/openpilot/ +ENV OPENPILOT_PATH /tmp/openpilot ENV PYTHONPATH ${OPENPILOT_PATH}:${PYTHONPATH} ENV POETRY_VIRUALENVS_CREATE false @@ -15,8 +15,8 @@ COPY ./openpilot ${OPENPILOT_PATH}/openpilot COPY ./body ${OPENPILOT_PATH}/body COPY ./third_party ${OPENPILOT_PATH}/third_party COPY ./site_scons ${OPENPILOT_PATH}/site_scons -COPY ./laika ${OPENPILOT_PATH}/laika COPY ./laika_repo ${OPENPILOT_PATH}/laika_repo +RUN ln -s ${OPENPILOT_PATH}/laika_repo ${OPENPILOT_PATH}/laika COPY ./rednose ${OPENPILOT_PATH}/rednose COPY ./rednose_repo ${OPENPILOT_PATH}/rednose_repo COPY ./tools ${OPENPILOT_PATH}/tools @@ -29,7 +29,7 @@ COPY ./selfdrive ${OPENPILOT_PATH}/selfdrive COPY ./system ${OPENPILOT_PATH}/system COPY ./*.md ${OPENPILOT_PATH}/ -RUN --mount=type=bind,source=.ci_cache/scons_cache,target=/tmp/scons_cache,rw scons -j$(nproc) +RUN --mount=type=bind,source=.ci_cache/scons_cache,target=/tmp/scons_cache,rw scons -j$(nproc) --cache-readonly RUN apt update && apt install doxygen -y COPY ./docs ${OPENPILOT_PATH}/docs @@ -38,5 +38,5 @@ WORKDIR ${OPENPILOT_PATH}/docs RUN make html FROM nginx:1.21 -COPY --from=0 /home/batman/openpilot/build/docs/html /usr/share/nginx/html +COPY --from=0 /tmp/openpilot/build/docs/html /usr/share/nginx/html COPY ./docs/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/tools/sim/Dockerfile.sim b/tools/sim/Dockerfile.sim index 8de5266841..800e9dac74 100644 --- a/tools/sim/Dockerfile.sim +++ b/tools/sim/Dockerfile.sim @@ -9,26 +9,29 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN cd $HOME && \ curl -O https://raw.githubusercontent.com/commaai/eon-neos-builder/master/devices/eon/home/.tmux.conf -ENV PYTHONPATH $HOME/openpilot:${PYTHONPATH} -RUN mkdir -p $HOME/openpilot - -COPY SConstruct $HOME/openpilot/ - -COPY ./openpilot $HOME/openpilot/openpilot -COPY ./body $HOME/openpilot/body -COPY ./third_party $HOME/openpilot/third_party -COPY ./site_scons $HOME/openpilot/site_scons -COPY ./rednose $HOME/openpilot/rednose -COPY ./laika $HOME/openpilot/laika -COPY ./common $HOME/openpilot/common -COPY ./opendbc $HOME/openpilot/opendbc -COPY ./cereal $HOME/openpilot/cereal -COPY ./panda $HOME/openpilot/panda -COPY ./selfdrive $HOME/openpilot/selfdrive -COPY ./system $HOME/openpilot/system -COPY ./tools $HOME/openpilot/tools - -WORKDIR $HOME/openpilot -RUN --mount=type=bind,source=.ci_cache/scons_cache,target=/tmp/scons_cache,rw scons -j$(nproc) +ENV OPENPILOT_PATH /tmp/openpilot +ENV PYTHONPATH ${OPENPILOT_PATH}:${PYTHONPATH} + +RUN mkdir -p ${OPENPILOT_PATH} +WORKDIR ${OPENPILOT_PATH} + +COPY SConstruct ${OPENPILOT_PATH} + +COPY ./openpilot ${OPENPILOT_PATH}/openpilot +COPY ./body ${OPENPILOT_PATH}/body +COPY ./third_party ${OPENPILOT_PATH}/third_party +COPY ./site_scons ${OPENPILOT_PATH}/site_scons +COPY ./rednose ${OPENPILOT_PATH}/rednose +COPY ./laika_repo ${OPENPILOT_PATH}/laika_repo +RUN ln -s ${OPENPILOT_PATH}/laika_repo ${OPENPILOT_PATH}/laika +COPY ./common ${OPENPILOT_PATH}/common +COPY ./opendbc ${OPENPILOT_PATH}/opendbc +COPY ./cereal ${OPENPILOT_PATH}/cereal +COPY ./panda ${OPENPILOT_PATH}/panda +COPY ./selfdrive ${OPENPILOT_PATH}/selfdrive +COPY ./system ${OPENPILOT_PATH}/system +COPY ./tools ${OPENPILOT_PATH}/tools + +RUN --mount=type=bind,source=.ci_cache/scons_cache,target=/tmp/scons_cache,rw scons -j$(nproc) --cache-readonly RUN python -c "from openpilot.selfdrive.test.helpers import set_params_enabled; set_params_enabled()" From c36774dfba513f6ea64cff06b215c355ee059dff Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 28 Aug 2023 16:57:49 +0800 Subject: [PATCH 10/13] ui: rename QDialogBase to DialogBase (#29675) rename QDialogBase to DialogBase --- selfdrive/ui/qt/widgets/input.cc | 14 +++++++------- selfdrive/ui/qt/widgets/input.h | 10 +++++----- selfdrive/ui/qt/widgets/prime.cc | 2 +- selfdrive/ui/qt/widgets/prime.h | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/selfdrive/ui/qt/widgets/input.cc b/selfdrive/ui/qt/widgets/input.cc index 49fbdff222..52d0c5cd6e 100644 --- a/selfdrive/ui/qt/widgets/input.cc +++ b/selfdrive/ui/qt/widgets/input.cc @@ -9,7 +9,7 @@ #include "selfdrive/ui/qt/widgets/scrollview.h" -QDialogBase::QDialogBase(QWidget *parent) : QDialog(parent) { +DialogBase::DialogBase(QWidget *parent) : QDialog(parent) { Q_ASSERT(parent != nullptr); parent->installEventFilter(this); @@ -19,7 +19,7 @@ QDialogBase::QDialogBase(QWidget *parent) : QDialog(parent) { color: white; font-family: Inter; } - QDialogBase { + DialogBase { background-color: black; } QPushButton { @@ -36,19 +36,19 @@ QDialogBase::QDialogBase(QWidget *parent) : QDialog(parent) { )"); } -bool QDialogBase::eventFilter(QObject *o, QEvent *e) { +bool DialogBase::eventFilter(QObject *o, QEvent *e) { if (o == parent() && e->type() == QEvent::Hide) { reject(); } return QDialog::eventFilter(o, e); } -int QDialogBase::exec() { +int DialogBase::exec() { setMainWindow(this); return QDialog::exec(); } -InputDialog::InputDialog(const QString &title, QWidget *parent, const QString &subtitle, bool secret) : QDialogBase(parent) { +InputDialog::InputDialog(const QString &title, QWidget *parent, const QString &subtitle, bool secret) : DialogBase(parent) { main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(50, 55, 50, 50); main_layout->setSpacing(0); @@ -188,7 +188,7 @@ void InputDialog::setMinLength(int length) { // ConfirmationDialog ConfirmationDialog::ConfirmationDialog(const QString &prompt_text, const QString &confirm_text, const QString &cancel_text, - const bool rich, QWidget *parent) : QDialogBase(parent) { + const bool rich, QWidget *parent) : DialogBase(parent) { QFrame *container = new QFrame(this); container->setStyleSheet(R"( QFrame { background-color: #1B1B1B; color: #C9C9C9; } @@ -245,7 +245,7 @@ bool ConfirmationDialog::rich(const QString &prompt_text, QWidget *parent) { // MultiOptionDialog -MultiOptionDialog::MultiOptionDialog(const QString &prompt_text, const QStringList &l, const QString ¤t, QWidget *parent) : QDialogBase(parent) { +MultiOptionDialog::MultiOptionDialog(const QString &prompt_text, const QStringList &l, const QString ¤t, QWidget *parent) : DialogBase(parent) { QFrame *container = new QFrame(this); container->setStyleSheet(R"( QFrame { background-color: #1B1B1B; } diff --git a/selfdrive/ui/qt/widgets/input.h b/selfdrive/ui/qt/widgets/input.h index e6c0fba86d..917ea21b57 100644 --- a/selfdrive/ui/qt/widgets/input.h +++ b/selfdrive/ui/qt/widgets/input.h @@ -10,18 +10,18 @@ #include "selfdrive/ui/qt/widgets/keyboard.h" -class QDialogBase : public QDialog { +class DialogBase : public QDialog { Q_OBJECT protected: - QDialogBase(QWidget *parent); + DialogBase(QWidget *parent); bool eventFilter(QObject *o, QEvent *e) override; public slots: int exec() override; }; -class InputDialog : public QDialogBase { +class InputDialog : public DialogBase { Q_OBJECT public: @@ -50,7 +50,7 @@ signals: void emitText(const QString &text); }; -class ConfirmationDialog : public QDialogBase { +class ConfirmationDialog : public DialogBase { Q_OBJECT public: @@ -61,7 +61,7 @@ public: static bool rich(const QString &prompt_text, QWidget *parent); }; -class MultiOptionDialog : public QDialogBase { +class MultiOptionDialog : public DialogBase { Q_OBJECT public: diff --git a/selfdrive/ui/qt/widgets/prime.cc b/selfdrive/ui/qt/widgets/prime.cc index 57d9d87a64..324d6cf6ae 100644 --- a/selfdrive/ui/qt/widgets/prime.cc +++ b/selfdrive/ui/qt/widgets/prime.cc @@ -68,7 +68,7 @@ void PairingQRWidget::paintEvent(QPaintEvent *e) { } -PairingPopup::PairingPopup(QWidget *parent) : QDialogBase(parent) { +PairingPopup::PairingPopup(QWidget *parent) : DialogBase(parent) { QHBoxLayout *hlayout = new QHBoxLayout(this); hlayout->setContentsMargins(0, 0, 0, 0); hlayout->setSpacing(0); diff --git a/selfdrive/ui/qt/widgets/prime.h b/selfdrive/ui/qt/widgets/prime.h index 227a0f31c1..63341c4cea 100644 --- a/selfdrive/ui/qt/widgets/prime.h +++ b/selfdrive/ui/qt/widgets/prime.h @@ -28,7 +28,7 @@ private slots: // pairing popup widget -class PairingPopup : public QDialogBase { +class PairingPopup : public DialogBase { Q_OBJECT public: From 72e2e2c9ec4e3a42cf35c23dfc0d66ea0565ace6 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 28 Aug 2023 10:26:19 -0700 Subject: [PATCH 11/13] pytest: strict config (#29676) * pytest: strict config * collection works * fixes --- poetry.lock | 45 ++++++++++++++++++--------- pyproject.toml | 6 ++-- system/loggerd/tests/test_uploader.py | 4 +-- tools/plotjuggler/test_plotjuggler.py | 25 +++++++-------- 4 files changed, 49 insertions(+), 31 deletions(-) diff --git a/poetry.lock b/poetry.lock index c5d7b0e28f..b021e0011e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "aiohttp" @@ -2383,14 +2383,7 @@ files = [ ] [package.dependencies] -numpy = [ - {version = ">=1.21.2", markers = "python_version >= \"3.10\""}, - {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\""}, - {version = ">=1.23.5", markers = "python_version >= \"3.11\""}, - {version = ">=1.19.3", markers = "python_version >= \"3.6\" and platform_system == \"Linux\" and platform_machine == \"aarch64\" or python_version >= \"3.9\""}, - {version = ">=1.17.0", markers = "python_version >= \"3.7\""}, - {version = ">=1.17.3", markers = "python_version >= \"3.8\""}, -] +numpy = {version = ">=1.23.5", markers = "python_version >= \"3.11\""} [[package]] name = "packaging" @@ -2438,10 +2431,7 @@ files = [ ] [package.dependencies] -numpy = [ - {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, - {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, -] +numpy = {version = ">=1.23.2", markers = "python_version >= \"3.11\""} python-dateutil = ">=2.8.2" pytz = ">=2020.1" tzdata = ">=2022.1" @@ -3243,6 +3233,33 @@ files = [ attrs = ">=19.2.0" pytest = ">=7.0" +[[package]] +name = "pytest-timeout" +version = "2.1.0" +description = "pytest plugin to abort hanging tests" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pytest-timeout-2.1.0.tar.gz", hash = "sha256:c07ca07404c612f8abbe22294b23c368e2e5104b521c1790195561f37e1ac3d9"}, + {file = "pytest_timeout-2.1.0-py3-none-any.whl", hash = "sha256:f6f50101443ce70ad325ceb4473c4255e9d74e3c7cd0ef827309dfa4c0d975c6"}, +] + +[package.dependencies] +pytest = ">=5.0.0" + +[[package]] +name = "pytest-timeouts" +version = "1.2.1" +description = "Linux-only Pytest plugin to control durations of various test case execution phases" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pytest-timeouts-1.2.1.tar.gz", hash = "sha256:390351afc7ecb422ea0ec38081e0acd91cad416b383944a9a3358087de50c2fb"}, +] + +[package.dependencies] +pytest = ">=3.1" + [[package]] name = "pytest-xdist" version = "3.3.1" @@ -4322,4 +4339,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "7e2bfde2719e7d7bb4b1627b0657e9ab4a9f4e1637d8b8ae6d5c80c7861e2052" +content-hash = "799e03aa1f3098c94a383f17b56275cd4140179bc457ff837b793fbcf7eb4b1e" diff --git a/pyproject.toml b/pyproject.toml index e350f070c4..b7952d3fa8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,8 @@ [tool.pytest.ini_options] minversion = "6.0" -addopts = "--ignore=panda/ --ignore=rednose_repo/ --ignore=tinygrad_repo/ --ignore=laika_repo/" +addopts = "--ignore=opendbc/ --ignore=panda/ --ignore=rednose_repo/ --ignore=tinygrad_repo/ --ignore=laika_repo/ -Werror --strict-config --strict-markers" python_files = "test_*.py" -timeout = "30" # you get this long by default +#timeout = "30" # you get this long by default [tool.mypy] python_version = "3.11" @@ -124,6 +124,8 @@ pytest = "*" pytest-cov = "*" pytest-subtests = "*" pytest-xdist = "*" +pytest-timeout = "*" +pytest-timeouts = "*" scipy = "*" sphinx = "*" sphinx-rtd-theme = "*" diff --git a/system/loggerd/tests/test_uploader.py b/system/loggerd/tests/test_uploader.py index bf21d8d7a9..6e2f86d6ca 100755 --- a/system/loggerd/tests/test_uploader.py +++ b/system/loggerd/tests/test_uploader.py @@ -14,7 +14,7 @@ from openpilot.system.loggerd.uploader import uploader_fn, UPLOAD_ATTR_NAME, UPL from openpilot.system.loggerd.tests.loggerd_tests_common import UploaderTestCase -class TestLogHandler(logging.Handler): +class FakeLogHandler(logging.Handler): def __init__(self): logging.Handler.__init__(self) self.reset() @@ -33,7 +33,7 @@ class TestLogHandler(logging.Handler): except Exception: pass -log_handler = TestLogHandler() +log_handler = FakeLogHandler() cloudlog.addHandler(log_handler) diff --git a/tools/plotjuggler/test_plotjuggler.py b/tools/plotjuggler/test_plotjuggler.py index e29e33f921..b002331cd7 100755 --- a/tools/plotjuggler/test_plotjuggler.py +++ b/tools/plotjuggler/test_plotjuggler.py @@ -18,19 +18,18 @@ class TestPlotJuggler(unittest.TestCase): install() pj = os.path.join(PJ_DIR, "juggle.py") - p = subprocess.Popen(f'QT_QPA_PLATFORM=offscreen {pj} --demo None 1 --qlog', - stderr=subprocess.PIPE, shell=True, start_new_session=True) - - # Wait for "Done reading Rlog data" signal from the plugin - output = "\n" - with Timeout(180, error_msg=output): - while output.splitlines()[-1] != "Done reading Rlog data": - output += p.stderr.readline().decode("utf-8") - - # ensure plotjuggler didn't crash after exiting the plugin - time.sleep(15) - self.assertEqual(p.poll(), None) - os.killpg(os.getpgid(p.pid), signal.SIGTERM) + with subprocess.Popen(f'QT_QPA_PLATFORM=offscreen {pj} --demo None 1 --qlog', + stderr=subprocess.PIPE, shell=True, start_new_session=True) as p: + # Wait for "Done reading Rlog data" signal from the plugin + output = "\n" + with Timeout(180, error_msg=output): + while output.splitlines()[-1] != "Done reading Rlog data": + output += p.stderr.readline().decode("utf-8") + + # ensure plotjuggler didn't crash after exiting the plugin + time.sleep(15) + self.assertEqual(p.poll(), None) + os.killpg(os.getpgid(p.pid), signal.SIGTERM) # TODO: also test that layouts successfully load def test_layouts(self): From eafdcb89e4a7b411a553da86eff3662ca1218acd Mon Sep 17 00:00:00 2001 From: Joshua Mack Date: Mon, 28 Aug 2023 13:30:15 -0400 Subject: [PATCH 12/13] Car docs: update alpha longitudinal name (#29670) * Update Footnote 1 Updated Footnote 1 for new name for toggle "openpilot Longitudinal Control (Alpha)" as well as made it clearer on how to change to devel or master-ci branches, taken from comma.ai blog (https://blog.comma.ai/090release/#experimental-longitudinal-control). * Add 3X * Added to Docs_definitions * just update name * fix * fix --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 2 +- selfdrive/car/docs_definitions.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 9ded53f201..ae977f16e3 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -268,7 +268,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Volkswagen|Touran 2016-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 three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| ### Footnotes -1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`.
+1openpilot Longitudinal Control (Alpha) is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`.
2By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace stock ACC. NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).
3Refers only to the Focus Mk4 (C519) available in Europe/China/Taiwan/Australasia, not the Focus Mk3 (C346) in North and South America/Southeast Asia.
4Requires a community built ASCM harness. NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).
diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index 71353efac9..60f9494708 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -176,8 +176,8 @@ CarFootnote = namedtuple("CarFootnote", ["text", "column", "docs_only", "shop_fo class CommonFootnote(Enum): EXP_LONG_AVAIL = CarFootnote( - "Experimental openpilot longitudinal control is available behind a toggle; " + - "the toggle is only available in non-release branches such as `devel` or `master-ci`. ", + "openpilot Longitudinal Control (Alpha) is available behind a toggle; " + + "the toggle is only available in non-release branches such as `devel` or `master-ci`.", Column.LONGITUDINAL, docs_only=True) EXP_LONG_DSU = CarFootnote( "By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. " + From 4755a30e75b6336ff9b430e2392e71d32b5befb6 Mon Sep 17 00:00:00 2001 From: Korben Date: Mon, 28 Aug 2023 19:38:42 +0200 Subject: [PATCH 13/13] Update French translation (#29664) * Update French translation - main_fr.ts Hello I noticed that some translations were sticking out a bit in the new interface, so I'm proposing an update to correct this. I've arranged for the translations that cause problems to have the same number of letters including spaces as the original sentence so that they fit in the UI. @maxime-desroches if you can give me your feedback, that would be very kind. Thank you. * Update selfdrive/ui/translations/main_fr.ts Co-authored-by: Maxime Desroches --------- Co-authored-by: Shane Smiskol Co-authored-by: Maxime Desroches --- selfdrive/ui/translations/main_fr.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/ui/translations/main_fr.ts b/selfdrive/ui/translations/main_fr.ts index 5908db1b2e..79c4ae5596 100644 --- a/selfdrive/ui/translations/main_fr.ts +++ b/selfdrive/ui/translations/main_fr.ts @@ -517,7 +517,7 @@ PrimeAdWidget Upgrade Now - Mettre à niveau maintenant + Mettre à niveau Become a comma prime member at connect.comma.ai @@ -860,7 +860,7 @@ Cela peut prendre jusqu'à une minute. SoftwarePanel Updates are only downloaded while the car is off. - Les mises à jour sont téléchargées uniquement lorsque la voiture est éteinte. + Les MàJ sont téléchargées uniquement si la voiture est éteinte. Current Version @@ -1174,7 +1174,7 @@ Cela peut prendre jusqu'à une minute. WiFiPromptWidget Setup Wi-Fi - Configurer le Wi-Fi + Configurer Wi-Fi Connect to Wi-Fi to upload driving data and help improve openpilot