diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 319ca4547c..1ea4d44dc4 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -16,7 +16,7 @@ if arch == "Darwin": qt_env['CXXFLAGS'] += ["-Wno-deprecated-declarations"] qt_util = qt_env.Library("qt_util", ["#selfdrive/ui/qt/api.cc", "#selfdrive/ui/qt/util.cc"], LIBS=base_libs) -widgets_src = ["ui.cc", "qt/widgets/input.cc", "qt/widgets/wifi.cc", +widgets_src = ["qt/widgets/input.cc", "qt/widgets/wifi.cc", "qt/prime_state.cc", "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", @@ -26,7 +26,7 @@ widgets = qt_env.Library("qt_widgets", widgets_src, LIBS=base_libs) Export('widgets') qt_libs = [widgets, qt_util] + base_libs -qt_src = ["main.cc", "qt/sidebar.cc", "qt/body.cc", +qt_src = ["main.cc", "ui.cc", "qt/sidebar.cc", "qt/body.cc", "qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc", "qt/offroad/software_settings.cc", "qt/offroad/onboarding.cc", "qt/offroad/driverview.cc", "qt/offroad/experimental_mode.cc", diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index af946c7987..648f3685c7 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -150,9 +150,8 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { left_widget->addWidget(new PrimeAdWidget); left_widget->setStyleSheet("border-radius: 10px;"); - left_widget->setCurrentIndex(uiState()->hasPrime() ? 0 : 1); - connect(uiState(), &UIState::primeChanged, [=](bool prime) { - left_widget->setCurrentIndex(prime ? 0 : 1); + connect(uiState()->prime_state, &PrimeState::changed, [left_widget]() { + left_widget->setCurrentIndex(uiState()->prime_state->isSubscribed() ? 0 : 1); }); home_layout->addWidget(left_widget, 1); diff --git a/selfdrive/ui/qt/network/networking.cc b/selfdrive/ui/qt/network/networking.cc index 250fa0fbf8..22d9c01efe 100644 --- a/selfdrive/ui/qt/network/networking.cc +++ b/selfdrive/ui/qt/network/networking.cc @@ -6,7 +6,6 @@ #include #include -#include "selfdrive/ui/ui.h" #include "selfdrive/ui/qt/qt_window.h" #include "selfdrive/ui/qt/util.h" #include "selfdrive/ui/qt/widgets/controls.h" @@ -73,6 +72,11 @@ Networking::Networking(QWidget* parent, bool show_advanced) : QFrame(parent) { main_layout->setCurrentWidget(wifiScreen); } +void Networking::setPrimeType(PrimeState::Type type) { + an->setGsmVisible(type == PrimeState::PRIME_TYPE_NONE || type == PrimeState::PRIME_TYPE_LITE); + wifi->ipv4_forward = (type == PrimeState::PRIME_TYPE_NONE || type == PrimeState::PRIME_TYPE_LITE); +} + void Networking::refresh() { wifiWidget->refresh(); an->refresh(); @@ -204,17 +208,16 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid // Set initial config wifi->updateGsmSettings(roamingEnabled, QString::fromStdString(params.get("GsmApn")), metered); - connect(uiState(), &UIState::primeTypeChanged, this, [=](PrimeType prime_type) { - bool gsmVisible = prime_type == PrimeType::PRIME_TYPE_NONE || prime_type == PrimeType::PRIME_TYPE_LITE; - roamingToggle->setVisible(gsmVisible); - editApnButton->setVisible(gsmVisible); - meteredToggle->setVisible(gsmVisible); - }); - main_layout->addWidget(new ScrollView(list, this)); main_layout->addStretch(1); } +void AdvancedNetworking::setGsmVisible(bool visible) { + roamingToggle->setVisible(visible); + editApnButton->setVisible(visible); + meteredToggle->setVisible(visible); +} + void AdvancedNetworking::refresh() { ipLabel->setText(wifi->ipv4_address); tetheringToggle->setEnabled(true); diff --git a/selfdrive/ui/qt/network/networking.h b/selfdrive/ui/qt/network/networking.h index 9b6af005ea..4fd604039b 100644 --- a/selfdrive/ui/qt/network/networking.h +++ b/selfdrive/ui/qt/network/networking.h @@ -3,6 +3,7 @@ #include #include "selfdrive/ui/qt/network/wifi_manager.h" +#include "selfdrive/ui/qt/prime_state.h" #include "selfdrive/ui/qt/widgets/input.h" #include "selfdrive/ui/qt/widgets/ssh_keys.h" #include "selfdrive/ui/qt/widgets/toggle.h" @@ -56,6 +57,7 @@ class AdvancedNetworking : public QWidget { Q_OBJECT public: explicit AdvancedNetworking(QWidget* parent = 0, WifiManager* wifi = 0); + void setGsmVisible(bool visible); private: LabelControl* ipLabel; @@ -81,6 +83,7 @@ class Networking : public QFrame { public: explicit Networking(QWidget* parent = 0, bool show_advanced = true); + void setPrimeType(PrimeState::Type type); WifiManager* wifi = nullptr; private: diff --git a/selfdrive/ui/qt/network/wifi_manager.cc b/selfdrive/ui/qt/network/wifi_manager.cc index b0c9535273..ddf13d26b7 100644 --- a/selfdrive/ui/qt/network/wifi_manager.cc +++ b/selfdrive/ui/qt/network/wifi_manager.cc @@ -2,10 +2,6 @@ #include -#include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/widgets/prime.h" - -#include "common/params.h" #include "common/swaglog.h" #include "selfdrive/ui/qt/util.h" @@ -445,9 +441,6 @@ void WifiManager::addTetheringConnection() { } void WifiManager::tetheringActivated(QDBusPendingCallWatcher *call) { - int prime_type = uiState()->primeType(); - int ipv4_forward = (prime_type == PrimeType::PRIME_TYPE_NONE || prime_type == PrimeType::PRIME_TYPE_LITE); - if (!ipv4_forward) { QTimer::singleShot(5000, this, [=] { qWarning() << "net.ipv4.ip_forward = 0"; diff --git a/selfdrive/ui/qt/network/wifi_manager.h b/selfdrive/ui/qt/network/wifi_manager.h index 2f6a1829d7..5d18b87d86 100644 --- a/selfdrive/ui/qt/network/wifi_manager.h +++ b/selfdrive/ui/qt/network/wifi_manager.h @@ -42,6 +42,7 @@ public: QMap seenNetworks; QMap knownConnections; QString ipv4_address; + bool ipv4_forward = false; explicit WifiManager(QObject* parent); void start(); diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index fc92a471d6..7024a2a802 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -247,8 +247,8 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { }); addItem(translateBtn); - QObject::connect(uiState(), &UIState::primeTypeChanged, [this] (PrimeType type) { - pair_device->setVisible(type == PrimeType::PRIME_TYPE_UNPAIRED); + QObject::connect(uiState()->prime_state, &PrimeState::changed, [this] (PrimeState::Type type) { + pair_device->setVisible(type == PrimeState::PRIME_TYPE_UNPAIRED); }); QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { for (auto btn : findChildren()) { @@ -335,11 +335,6 @@ void DevicePanel::poweroff() { } } -void DevicePanel::showEvent(QShowEvent *event) { - pair_device->setVisible(uiState()->primeType() == PrimeType::PRIME_TYPE_UNPAIRED); - ListWidget::showEvent(event); -} - void SettingsWindow::showEvent(QShowEvent *event) { setCurrentPanel(0); } @@ -386,9 +381,12 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { TogglesPanel *toggles = new TogglesPanel(this); QObject::connect(this, &SettingsWindow::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription); + auto networking = new Networking(this); + QObject::connect(uiState()->prime_state, &PrimeState::changed, networking, &Networking::setPrimeType); + QList> panels = { {tr("Device"), device}, - {tr("Network"), new Networking(this)}, + {tr("Network"), networking}, {tr("Toggles"), toggles}, {tr("Software"), new SoftwarePanel(this)}, }; diff --git a/selfdrive/ui/qt/offroad/settings.h b/selfdrive/ui/qt/offroad/settings.h index 35a044bdd2..68ba0d1898 100644 --- a/selfdrive/ui/qt/offroad/settings.h +++ b/selfdrive/ui/qt/offroad/settings.h @@ -42,7 +42,6 @@ class DevicePanel : public ListWidget { Q_OBJECT public: explicit DevicePanel(SettingsWindow *parent); - void showEvent(QShowEvent *event) override; signals: void reviewTrainingGuide(); diff --git a/selfdrive/ui/qt/prime_state.cc b/selfdrive/ui/qt/prime_state.cc new file mode 100644 index 0000000000..f12daf1e3c --- /dev/null +++ b/selfdrive/ui/qt/prime_state.cc @@ -0,0 +1,48 @@ +#include "selfdrive/ui/qt/prime_state.h" + +#include + +#include "selfdrive/ui/qt/api.h" +#include "selfdrive/ui/qt/request_repeater.h" +#include "selfdrive/ui/qt/util.h" + +PrimeState::PrimeState(QObject* parent) : QObject(parent) { + const char *env_prime_type = std::getenv("PRIME_TYPE"); + auto type = env_prime_type ? env_prime_type : Params().get("PrimeType"); + + if (!type.empty()) { + prime_type = static_cast(std::atoi(type.c_str())); + } + + if (auto dongleId = getDongleId()) { + QString url = CommaApi::BASE_URL + "/v1.1/devices/" + *dongleId + "/"; + RequestRepeater* repeater = new RequestRepeater(this, url, "ApiCache_Device", 5); + QObject::connect(repeater, &RequestRepeater::requestDone, this, &PrimeState::handleReply); + } + + // Emit the initial state change + QTimer::singleShot(1, [this]() { emit changed(prime_type); }); +} + +void PrimeState::handleReply(const QString& response, bool success) { + if (!success) return; + + QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); + if (doc.isNull()) { + qDebug() << "JSON Parse failed on getting pairing and PrimeState status"; + return; + } + + QJsonObject json = doc.object(); + bool is_paired = json["is_paired"].toBool(); + auto type = static_cast(json["prime_type"].toInt()); + setType(is_paired ? type : PrimeState::PRIME_TYPE_UNPAIRED); +} + +void PrimeState::setType(PrimeState::Type type) { + if (type != prime_type) { + prime_type = type; + Params().put("PrimeType", std::to_string(prime_type)); + emit changed(prime_type); + } +} diff --git a/selfdrive/ui/qt/prime_state.h b/selfdrive/ui/qt/prime_state.h new file mode 100644 index 0000000000..0e2e3bb043 --- /dev/null +++ b/selfdrive/ui/qt/prime_state.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +class PrimeState : public QObject { + Q_OBJECT + +public: + + enum Type { + PRIME_TYPE_UNKNOWN = -2, + PRIME_TYPE_UNPAIRED = -1, + PRIME_TYPE_NONE = 0, + PRIME_TYPE_MAGENTA = 1, + PRIME_TYPE_LITE = 2, + PRIME_TYPE_BLUE = 3, + PRIME_TYPE_MAGENTA_NEW = 4, + PRIME_TYPE_PURPLE = 5, + }; + + PrimeState(QObject *parent); + void setType(PrimeState::Type type); + inline PrimeState::Type currentType() const { return prime_type; } + inline bool isSubscribed() const { return prime_type > PrimeState::PRIME_TYPE_NONE; } + +signals: + void changed(PrimeState::Type prime_type); + +private: + void handleReply(const QString &response, bool success); + + PrimeState::Type prime_type = PrimeState::PRIME_TYPE_UNKNOWN; +}; diff --git a/selfdrive/ui/qt/widgets/prime.cc b/selfdrive/ui/qt/widgets/prime.cc index f86258ea4f..9bc96fcdad 100644 --- a/selfdrive/ui/qt/widgets/prime.cc +++ b/selfdrive/ui/qt/widgets/prime.cc @@ -246,33 +246,12 @@ SetupWidget::SetupWidget(QWidget* parent) : QFrame(parent) { sp_retain.setRetainSizeWhenHidden(true); setSizePolicy(sp_retain); - // set up API requests - if (auto dongleId = getDongleId()) { - QString url = CommaApi::BASE_URL + "/v1.1/devices/" + *dongleId + "/"; - RequestRepeater* repeater = new RequestRepeater(this, url, "ApiCache_Device", 5); - - QObject::connect(repeater, &RequestRepeater::requestDone, this, &SetupWidget::replyFinished); - } -} - -void SetupWidget::replyFinished(const QString &response, bool success) { - if (!success) return; - - QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); - if (doc.isNull()) { - qDebug() << "JSON Parse failed on getting pairing and prime status"; - return; - } - - QJsonObject json = doc.object(); - bool is_paired = json["is_paired"].toBool(); - PrimeType prime_type = static_cast(json["prime_type"].toInt()); - uiState()->setPrimeType(is_paired ? prime_type : PrimeType::PRIME_TYPE_UNPAIRED); - - if (!is_paired) { - mainLayout->setCurrentIndex(0); - } else { - popup->reject(); - mainLayout->setCurrentIndex(1); - } + QObject::connect(uiState()->prime_state, &PrimeState::changed, [this](PrimeState::Type type) { + if (type == PrimeState::PRIME_TYPE_UNPAIRED) { + mainLayout->setCurrentIndex(0); // Display "Pair your device" widget + } else { + popup->reject(); + mainLayout->setCurrentIndex(1); // Display Wi-Fi prompt widget + } + }); } diff --git a/selfdrive/ui/qt/widgets/prime.h b/selfdrive/ui/qt/widgets/prime.h index eac71bcddb..d1ba334e81 100644 --- a/selfdrive/ui/qt/widgets/prime.h +++ b/selfdrive/ui/qt/widgets/prime.h @@ -66,7 +66,4 @@ signals: private: PairingPopup *popup; QStackedWidget *mainLayout; - -private slots: - void replyFinished(const QString &response, bool success); }; diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 1a3198c936..cbe05edfc9 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -210,13 +210,8 @@ UIState::UIState(QObject *parent) : QObject(parent) { "pandaStates", "carParams", "driverMonitoringState", "carState", "driverStateV2", "wideRoadCameraState", "managerState", "selfdriveState", }); - - Params params; - language = QString::fromStdString(params.get("LanguageSetting")); - auto prime_value = params.get("PrimeType"); - if (!prime_value.empty()) { - prime_type = static_cast(std::atoi(prime_value.c_str())); - } + prime_state = new PrimeState(this); + language = QString::fromStdString(Params().get("LanguageSetting")); // update timer timer = new QTimer(this); @@ -229,31 +224,12 @@ void UIState::update() { update_state(this); updateStatus(); - if (std::getenv("PRIME_TYPE")) { - setPrimeType((PrimeType)atoi(std::getenv("PRIME_TYPE"))); - } - if (sm->frame % UI_FREQ == 0) { watchdog_kick(nanos_since_boot()); } emit uiUpdate(*this); } -void UIState::setPrimeType(PrimeType type) { - if (type != prime_type) { - bool prev_prime = hasPrime(); - - prime_type = type; - Params().put("PrimeType", std::to_string(prime_type)); - emit primeTypeChanged(prime_type); - - bool prime = hasPrime(); - if (prev_prime != prime) { - emit primeChanged(prime); - } - } -} - Device::Device(QObject *parent) : brightness_filter(BACKLIGHT_OFFROAD, BACKLIGHT_TS, BACKLIGHT_DT), QObject(parent) { setAwake(true); resetInteractiveTimeout(); diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index 73b8c5ddeb..8cf2f52d58 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -15,6 +15,7 @@ #include "common/params.h" #include "common/timing.h" #include "system/hardware/hw.h" +#include "selfdrive/ui/qt/prime_state.h" const int UI_BORDER_SIZE = 30; const int UI_HEADER_HEIGHT = 420; @@ -40,17 +41,6 @@ typedef enum UIStatus { STATUS_ENGAGED, } UIStatus; -enum PrimeType { - PRIME_TYPE_UNKNOWN = -2, - PRIME_TYPE_UNPAIRED = -1, - PRIME_TYPE_NONE = 0, - PRIME_TYPE_MAGENTA = 1, - PRIME_TYPE_LITE = 2, - PRIME_TYPE_BLUE = 3, - PRIME_TYPE_MAGENTA_NEW = 4, - PRIME_TYPE_PURPLE = 5, -}; - const QColor bg_colors [] = { [STATUS_DISENGAGED] = QColor(0x17, 0x33, 0x49, 0xc8), [STATUS_OVERRIDE] = QColor(0x91, 0x9b, 0x95, 0xf1), @@ -94,10 +84,6 @@ public: return scene.started && (*sm)["selfdriveState"].getSelfdriveState().getEnabled(); } - void setPrimeType(PrimeType type); - inline PrimeType primeType() const { return prime_type; } - inline bool hasPrime() const { return prime_type > PrimeType::PRIME_TYPE_NONE; } - int fb_w = 0, fb_h = 0; std::unique_ptr sm; @@ -108,12 +94,11 @@ public: QString language; QTransform car_space_transform; + PrimeState *prime_state; signals: void uiUpdate(const UIState &s); void offroadTransition(bool offroad); - void primeChanged(bool prime); - void primeTypeChanged(PrimeType prime_type); private slots: void update(); @@ -121,7 +106,6 @@ private slots: private: QTimer *timer; bool started_prev = false; - PrimeType prime_type = PrimeType::PRIME_TYPE_UNKNOWN; }; UIState *uiState();