|  |  |  | #include "selfdrive/ui/qt/offroad/settings.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <cassert>
 | 
					
						
							|  |  |  | #include <cmath>
 | 
					
						
							|  |  |  | #include <string>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <QDebug>
 | 
					
						
							|  |  |  | #include <QLabel>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "common/params.h"
 | 
					
						
							|  |  |  | #include "common/util.h"
 | 
					
						
							|  |  |  | #include "selfdrive/ui/ui.h"
 | 
					
						
							|  |  |  | #include "selfdrive/ui/qt/util.h"
 | 
					
						
							|  |  |  | #include "selfdrive/ui/qt/widgets/controls.h"
 | 
					
						
							|  |  |  | #include "selfdrive/ui/qt/widgets/input.h"
 | 
					
						
							|  |  |  | #include "system/hardware/hw.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SoftwarePanel::checkForUpdates() {
 | 
					
						
							|  |  |  |   std::system("pkill -SIGUSR1 -f selfdrive.updated");
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) {
 | 
					
						
							|  |  |  |   onroadLbl = new QLabel(tr("Updates are only downloaded while the car is off."));
 | 
					
						
							|  |  |  |   onroadLbl->setStyleSheet("font-size: 50px; font-weight: 400; text-align: left; padding-top: 30px; padding-bottom: 30px;");
 | 
					
						
							|  |  |  |   addItem(onroadLbl);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // current version
 | 
					
						
							|  |  |  |   versionLbl = new LabelControl(tr("Current Version"), "");
 | 
					
						
							|  |  |  |   addItem(versionLbl);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // download update btn
 | 
					
						
							|  |  |  |   downloadBtn = new ButtonControl(tr("Download"), tr("CHECK"));
 | 
					
						
							|  |  |  |   connect(downloadBtn, &ButtonControl::clicked, [=]() {
 | 
					
						
							|  |  |  |     downloadBtn->setEnabled(false);
 | 
					
						
							|  |  |  |     if (downloadBtn->text() == tr("CHECK")) {
 | 
					
						
							|  |  |  |       checkForUpdates();
 | 
					
						
							|  |  |  |     } else {
 | 
					
						
							|  |  |  |       std::system("pkill -SIGHUP -f selfdrive.updated");
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |   });
 | 
					
						
							|  |  |  |   addItem(downloadBtn);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // install update btn
 | 
					
						
							|  |  |  |   installBtn = new ButtonControl(tr("Install Update"), tr("INSTALL"));
 | 
					
						
							|  |  |  |   connect(installBtn, &ButtonControl::clicked, [=]() {
 | 
					
						
							|  |  |  |     installBtn->setEnabled(false);
 | 
					
						
							|  |  |  |     params.putBool("DoReboot", true);
 | 
					
						
							|  |  |  |   });
 | 
					
						
							|  |  |  |   addItem(installBtn);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // branch selecting
 | 
					
						
							|  |  |  |   targetBranchBtn = new ButtonControl(tr("Target Branch"), tr("SELECT"));
 | 
					
						
							|  |  |  |   connect(targetBranchBtn, &ButtonControl::clicked, [=]() {
 | 
					
						
							|  |  |  |     auto current = params.get("GitBranch");
 | 
					
						
							|  |  |  |     QStringList branches = QString::fromStdString(params.get("UpdaterAvailableBranches")).split(",");
 | 
					
						
							|  |  |  |     for (QString b : {current.c_str(), "devel-staging", "devel", "nightly", "master-ci", "master"}) {
 | 
					
						
							|  |  |  |       auto i = branches.indexOf(b);
 | 
					
						
							|  |  |  |       if (i >= 0) {
 | 
					
						
							|  |  |  |         branches.removeAt(i);
 | 
					
						
							|  |  |  |         branches.insert(0, b);
 | 
					
						
							|  |  |  |       }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QString cur = QString::fromStdString(params.get("UpdaterTargetBranch"));
 | 
					
						
							|  |  |  |     QString selection = MultiOptionDialog::getSelection(tr("Select a branch"), branches, cur, this);
 | 
					
						
							|  |  |  |     if (!selection.isEmpty()) {
 | 
					
						
							|  |  |  |       params.put("UpdaterTargetBranch", selection.toStdString());
 | 
					
						
							|  |  |  |       targetBranchBtn->setValue(QString::fromStdString(params.get("UpdaterTargetBranch")));
 | 
					
						
							|  |  |  |       checkForUpdates();
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |   });
 | 
					
						
							|  |  |  |   if (!params.getBool("IsTestedBranch")) {
 | 
					
						
							|  |  |  |     addItem(targetBranchBtn);
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // uninstall button
 | 
					
						
							|  |  |  |   auto uninstallBtn = new ButtonControl(tr("Uninstall %1").arg(getBrand()), tr("UNINSTALL"));
 | 
					
						
							|  |  |  |   connect(uninstallBtn, &ButtonControl::clicked, [&]() {
 | 
					
						
							|  |  |  |     if (ConfirmationDialog::confirm(tr("Are you sure you want to uninstall?"), tr("Uninstall"), this)) {
 | 
					
						
							|  |  |  |       params.putBool("DoUninstall", true);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |   });
 | 
					
						
							|  |  |  |   addItem(uninstallBtn);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   fs_watch = new QFileSystemWatcher(this);
 | 
					
						
							|  |  |  |   QObject::connect(fs_watch, &QFileSystemWatcher::fileChanged, [=](const QString path) {
 | 
					
						
							|  |  |  |     updateLabels();
 | 
					
						
							|  |  |  |   });
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   connect(uiState(), &UIState::offroadTransition, [=](bool offroad) {
 | 
					
						
							|  |  |  |     is_onroad = !offroad;
 | 
					
						
							|  |  |  |     updateLabels();
 | 
					
						
							|  |  |  |   });
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   updateLabels();
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SoftwarePanel::showEvent(QShowEvent *event) {
 | 
					
						
							|  |  |  |   // nice for testing on PC
 | 
					
						
							|  |  |  |   installBtn->setEnabled(true);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   updateLabels();
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SoftwarePanel::updateLabels() {
 | 
					
						
							|  |  |  |   // add these back in case the files got removed
 | 
					
						
							|  |  |  |   fs_watch->addPath(QString::fromStdString(params.getParamPath("LastUpdateTime")));
 | 
					
						
							|  |  |  |   fs_watch->addPath(QString::fromStdString(params.getParamPath("UpdateFailedCount")));
 | 
					
						
							|  |  |  |   fs_watch->addPath(QString::fromStdString(params.getParamPath("UpdaterState")));
 | 
					
						
							|  |  |  |   fs_watch->addPath(QString::fromStdString(params.getParamPath("UpdateAvailable")));
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!isVisible()) {
 | 
					
						
							|  |  |  |     return;
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // updater only runs offroad
 | 
					
						
							|  |  |  |   onroadLbl->setVisible(is_onroad);
 | 
					
						
							|  |  |  |   downloadBtn->setVisible(!is_onroad);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // download update
 | 
					
						
							|  |  |  |   QString updater_state = QString::fromStdString(params.get("UpdaterState"));
 | 
					
						
							|  |  |  |   bool failed = std::atoi(params.get("UpdateFailedCount").c_str()) > 0;
 | 
					
						
							|  |  |  |   if (updater_state != "idle") {
 | 
					
						
							|  |  |  |     downloadBtn->setEnabled(false);
 | 
					
						
							|  |  |  |     downloadBtn->setValue(updater_state);
 | 
					
						
							|  |  |  |   } else {
 | 
					
						
							|  |  |  |     if (failed) {
 | 
					
						
							|  |  |  |       downloadBtn->setText("CHECK");
 | 
					
						
							|  |  |  |       downloadBtn->setValue("failed to check for update");
 | 
					
						
							|  |  |  |     } else if (params.getBool("UpdaterFetchAvailable")) {
 | 
					
						
							|  |  |  |       downloadBtn->setText("DOWNLOAD");
 | 
					
						
							|  |  |  |       downloadBtn->setValue("update available");
 | 
					
						
							|  |  |  |     } else {
 | 
					
						
							|  |  |  |       QString lastUpdate = "never";
 | 
					
						
							|  |  |  |       auto tm = params.get("LastUpdateTime");
 | 
					
						
							|  |  |  |       if (!tm.empty()) {
 | 
					
						
							|  |  |  |         lastUpdate = timeAgo(QDateTime::fromString(QString::fromStdString(tm + "Z"), Qt::ISODate));
 | 
					
						
							|  |  |  |       }
 | 
					
						
							|  |  |  |       downloadBtn->setText("CHECK");
 | 
					
						
							|  |  |  |       downloadBtn->setValue("up to date, last checked " + lastUpdate);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     downloadBtn->setEnabled(true);
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  |   targetBranchBtn->setValue(QString::fromStdString(params.get("UpdaterTargetBranch")));
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // current + new versions
 | 
					
						
							|  |  |  |   versionLbl->setText(QString::fromStdString(params.get("UpdaterCurrentDescription")));
 | 
					
						
							|  |  |  |   versionLbl->setDescription(QString::fromStdString(params.get("UpdaterCurrentReleaseNotes")));
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   installBtn->setVisible(!is_onroad && params.getBool("UpdateAvailable"));
 | 
					
						
							|  |  |  |   installBtn->setValue(QString::fromStdString(params.get("UpdaterNewDescription")));
 | 
					
						
							|  |  |  |   installBtn->setDescription(QString::fromStdString(params.get("UpdaterNewReleaseNotes")));
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   update();
 | 
					
						
							|  |  |  | }
 |