nopenpilot/selfdrive/ui/qt/setup/setup.cc

425 lines
12 KiB
C++
Raw Normal View History

2021-06-08 13:09:30 -06:00
#include "selfdrive/ui/qt/setup/setup.h"
#include <cstdio>
#include <cstdlib>
#include <sstream>
#include <QApplication>
#include <QLabel>
#include <QVBoxLayout>
#include <curl/curl.h>
#include "selfdrive/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/widgets/input.h"
const char* USER_AGENT = "AGNOSSetup-0.1";
const QString DASHCAM_URL = "https://dashcam.comma.ai";
2020-11-30 17:57:41 -07:00
void Setup::download(QString url) {
CURL *curl = curl_easy_init();
if (!curl) {
emit finished(false);
return;
}
2020-11-22 16:37:13 -07:00
char tmpfile[] = "/tmp/installer_XXXXXX";
FILE *fp = fdopen(mkstemp(tmpfile), "w");
curl_easy_setopt(curl, CURLOPT_URL, url.toStdString().c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
2020-11-30 18:02:24 -07:00
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
2020-12-01 00:32:08 -07:00
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
2020-11-30 18:02:24 -07:00
curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT);
int ret = curl_easy_perform(curl);
if (ret != CURLE_OK) {
emit finished(false);
return;
}
curl_easy_cleanup(curl);
fclose(fp);
2020-11-22 16:37:13 -07:00
rename(tmpfile, "/tmp/installer");
emit finished(true);
}
QWidget * Setup::low_voltage() {
QWidget *widget = new QWidget();
QVBoxLayout *main_layout = new QVBoxLayout(widget);
main_layout->setContentsMargins(55, 0, 55, 55);
main_layout->setSpacing(0);
// inner text layout: warning icon, title, and body
QVBoxLayout *inner_layout = new QVBoxLayout();
inner_layout->setContentsMargins(110, 144, 365, 0);
main_layout->addLayout(inner_layout);
QLabel *triangle = new QLabel();
triangle->setPixmap(QPixmap(ASSET_PATH + "offroad/icon_warning.png"));
inner_layout->addWidget(triangle, 0, Qt::AlignTop | Qt::AlignLeft);
inner_layout->addSpacing(80);
QLabel *title = new QLabel("WARNING: Low Voltage");
title->setStyleSheet("font-size: 90px; font-weight: 500; color: #FF594F;");
inner_layout->addWidget(title, 0, Qt::AlignTop | Qt::AlignLeft);
inner_layout->addSpacing(25);
QLabel *body = new QLabel("Power your device in a car with a harness or proceed at your own risk.");
body->setWordWrap(true);
body->setAlignment(Qt::AlignTop | Qt::AlignLeft);
body->setStyleSheet("font-size: 80px; font-weight: 300;");
inner_layout->addWidget(body);
inner_layout->addStretch();
// power off + continue buttons
QHBoxLayout *blayout = new QHBoxLayout();
blayout->setSpacing(50);
main_layout->addLayout(blayout, 0);
QPushButton *poweroff = new QPushButton("Power off");
poweroff->setObjectName("navBtn");
blayout->addWidget(poweroff);
QObject::connect(poweroff, &QPushButton::clicked, this, [=]() {
Hardware::poweroff();
});
QPushButton *cont = new QPushButton("Continue");
cont->setObjectName("navBtn");
blayout->addWidget(cont);
QObject::connect(cont, &QPushButton::clicked, this, &Setup::nextPage);
return widget;
}
QWidget * Setup::getting_started() {
QWidget *widget = new QWidget();
QHBoxLayout *main_layout = new QHBoxLayout(widget);
main_layout->setMargin(0);
QVBoxLayout *vlayout = new QVBoxLayout();
vlayout->setContentsMargins(165, 280, 100, 0);
main_layout->addLayout(vlayout);
QLabel *title = new QLabel("Getting Started");
title->setStyleSheet("font-size: 90px; font-weight: 500;");
vlayout->addWidget(title, 0, Qt::AlignTop | Qt::AlignLeft);
vlayout->addSpacing(90);
QLabel *desc = new QLabel("Before we get on the road, let’s finish installation and cover some details.");
desc->setWordWrap(true);
desc->setStyleSheet("font-size: 80px; font-weight: 300;");
vlayout->addWidget(desc, 0, Qt::AlignTop | Qt::AlignLeft);
2021-04-01 23:12:33 -06:00
vlayout->addStretch();
QPushButton *btn = new QPushButton();
btn->setIcon(QIcon(":/img_continue_triangle.svg"));
btn->setIconSize(QSize(54, 106));
btn->setFixedSize(310, 1080);
btn->setProperty("primary", true);
btn->setStyleSheet("border: none;");
main_layout->addWidget(btn, 0, Qt::AlignRight);
QObject::connect(btn, &QPushButton::clicked, this, &Setup::nextPage);
return widget;
}
QWidget * Setup::network_setup() {
QWidget *widget = new QWidget();
QVBoxLayout *main_layout = new QVBoxLayout(widget);
main_layout->setContentsMargins(55, 50, 55, 50);
// title
QLabel *title = new QLabel("Connect to Wi-Fi");
title->setStyleSheet("font-size: 90px; font-weight: 500;");
main_layout->addWidget(title, 0, Qt::AlignLeft | Qt::AlignTop);
main_layout->addSpacing(25);
// wifi widget
2021-07-28 15:55:42 -06:00
Networking *networking = new Networking(this, false);
networking->setStyleSheet("Networking {background-color: #292929; border-radius: 13px;}");
main_layout->addWidget(networking, 1);
main_layout->addSpacing(35);
// back + continue buttons
QHBoxLayout *blayout = new QHBoxLayout;
main_layout->addLayout(blayout);
blayout->setSpacing(50);
QPushButton *back = new QPushButton("Back");
back->setObjectName("navBtn");
QObject::connect(back, &QPushButton::clicked, this, &Setup::prevPage);
blayout->addWidget(back);
QPushButton *cont = new QPushButton();
cont->setObjectName("navBtn");
cont->setProperty("primary", true);
QObject::connect(cont, &QPushButton::clicked, this, &Setup::nextPage);
blayout->addWidget(cont);
// setup timer for testing internet connection
HttpRequest *request = new HttpRequest(this, false, 2500);
QObject::connect(request, &HttpRequest::requestDone, [=](bool success) {
cont->setEnabled(success);
2021-07-28 15:55:42 -06:00
if (success) {
const bool cell = networking->wifi->currentNetworkType() == NetworkType::CELL;
cont->setText(cell ? "Continue without Wi-Fi" : "Continue");
2021-07-28 15:55:42 -06:00
} else {
cont->setText("Waiting for internet");
}
repaint();
});
request->sendRequest(DASHCAM_URL);
QTimer *timer = new QTimer(this);
QObject::connect(timer, &QTimer::timeout, [=]() {
if (!request->active() && cont->isVisible()) {
request->sendRequest(DASHCAM_URL);
}
});
timer->start(1000);
return widget;
}
QWidget * radio_button(QString title, QButtonGroup *group) {
QPushButton *btn = new QPushButton(title);
btn->setCheckable(true);
group->addButton(btn);
btn->setStyleSheet(R"(
QPushButton {
height: 230;
padding-left: 100px;
padding-right: 100px;
text-align: left;
font-size: 80px;
font-weight: 400;
border-radius: 10px;
background-color: #4F4F4F;
}
QPushButton:checked {
background-color: #465BEA;
}
)");
// checkmark icon
QPixmap pix(":/img_circled_check.svg");
btn->setIcon(pix);
btn->setIconSize(QSize(0, 0));
btn->setLayoutDirection(Qt::RightToLeft);
QObject::connect(btn, &QPushButton::toggled, [=](bool checked) {
btn->setIconSize(checked ? QSize(104, 104) : QSize(0, 0));
});
return btn;
}
QWidget * Setup::software_selection() {
QWidget *widget = new QWidget();
QVBoxLayout *main_layout = new QVBoxLayout(widget);
main_layout->setContentsMargins(55, 50, 55, 50);
main_layout->setSpacing(0);
// title
QLabel *title = new QLabel("Choose Software to Install");
title->setStyleSheet("font-size: 90px; font-weight: 500;");
main_layout->addWidget(title, 0, Qt::AlignLeft | Qt::AlignTop);
main_layout->addSpacing(50);
// dashcam + custom radio buttons
QButtonGroup *group = new QButtonGroup(widget);
group->setExclusive(true);
QWidget *dashcam = radio_button("Dashcam", group);
main_layout->addWidget(dashcam);
main_layout->addSpacing(30);
QWidget *custom = radio_button("Custom Software", group);
main_layout->addWidget(custom);
main_layout->addStretch();
// back + continue buttons
QHBoxLayout *blayout = new QHBoxLayout;
main_layout->addLayout(blayout);
blayout->setSpacing(50);
QPushButton *back = new QPushButton("Back");
back->setObjectName("navBtn");
QObject::connect(back, &QPushButton::clicked, this, &Setup::prevPage);
blayout->addWidget(back);
QPushButton *cont = new QPushButton("Continue");
cont->setObjectName("navBtn");
cont->setEnabled(false);
cont->setProperty("primary", true);
blayout->addWidget(cont);
QObject::connect(cont, &QPushButton::clicked, [=]() {
auto w = currentWidget();
QTimer::singleShot(0, [=]() {
setCurrentWidget(downloading_widget);
});
QString url = DASHCAM_URL;
if (group->checkedButton() != dashcam) {
url = InputDialog::getText("Enter URL", this, "for Custom Software");
}
if (!url.isEmpty()) {
QTimer::singleShot(1000, this, [=]() {
download(url);
});
} else {
setCurrentWidget(w);
}
});
connect(group, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked), [=](QAbstractButton *btn) {
btn->setChecked(true);
cont->setEnabled(true);
});
return widget;
}
QWidget * Setup::downloading() {
QWidget *widget = new QWidget();
QVBoxLayout *main_layout = new QVBoxLayout(widget);
QLabel *txt = new QLabel("Downloading...");
txt->setStyleSheet("font-size: 90px; font-weight: 500;");
main_layout->addWidget(txt, 0, Qt::AlignCenter);
return widget;
}
QWidget * Setup::download_failed() {
QWidget *widget = new QWidget();
QVBoxLayout *main_layout = new QVBoxLayout(widget);
main_layout->setContentsMargins(55, 225, 55, 55);
main_layout->setSpacing(0);
QLabel *title = new QLabel("Download Failed");
title->setStyleSheet("font-size: 90px; font-weight: 500;");
main_layout->addWidget(title, 0, Qt::AlignTop | Qt::AlignLeft);
main_layout->addSpacing(67);
QLabel *body = new QLabel("Ensure the entered URL is valid, and the device’s internet connection is good.");
body->setWordWrap(true);
body->setAlignment(Qt::AlignTop | Qt::AlignLeft);
body->setStyleSheet("font-size: 80px; font-weight: 300; margin-right: 100px;");
main_layout->addWidget(body);
main_layout->addStretch();
// reboot + start over buttons
QHBoxLayout *blayout = new QHBoxLayout();
blayout->setSpacing(50);
main_layout->addLayout(blayout, 0);
QPushButton *reboot = new QPushButton("Reboot device");
reboot->setObjectName("navBtn");
blayout->addWidget(reboot);
QObject::connect(reboot, &QPushButton::clicked, this, [=]() {
Hardware::reboot();
});
QPushButton *restart = new QPushButton("Start over");
restart->setObjectName("navBtn");
restart->setProperty("primary", true);
blayout->addWidget(restart);
QObject::connect(restart, &QPushButton::clicked, this, [=]() {
2021-07-26 18:50:42 -06:00
setCurrentIndex(2);
});
widget->setStyleSheet(R"(
QLabel {
margin-left: 117;
}
)");
return widget;
}
void Setup::prevPage() {
setCurrentIndex(currentIndex() - 1);
}
void Setup::nextPage() {
2020-11-25 00:49:20 -07:00
setCurrentIndex(currentIndex() + 1);
}
Setup::Setup(QWidget *parent) : QStackedWidget(parent) {
std::stringstream buffer;
buffer << std::ifstream("/sys/class/hwmon/hwmon1/in1_input").rdbuf();
float voltage = (float)std::atoi(buffer.str().c_str()) / 1000.;
if (voltage < 7) {
addWidget(low_voltage());
}
2020-11-25 00:49:20 -07:00
addWidget(getting_started());
addWidget(network_setup());
addWidget(software_selection());
downloading_widget = downloading();
addWidget(downloading_widget);
failed_widget = download_failed();
addWidget(failed_widget);
2020-11-14 16:50:11 -07:00
QObject::connect(this, &Setup::finished, [=](bool success) {
// hide setup on success
qDebug() << "finished" << success;
if (success) {
QTimer::singleShot(3000, this, &QWidget::hide);
} else {
setCurrentWidget(failed_widget);
}
});
// TODO: revisit pressed bg color
setStyleSheet(R"(
2021-01-07 18:36:29 -07:00
* {
color: white;
font-family: Inter;
}
Setup {
background-color: black;
}
QPushButton#navBtn {
height: 160;
font-size: 55px;
font-weight: 400;
border-radius: 10px;
background-color: #333333;
}
QPushButton#navBtn:disabled, QPushButton[primary='true']:disabled {
color: #808080;
background-color: #333333;
}
QPushButton#navBtn:pressed {
background-color: #444444;
}
QPushButton[primary='true'], #navBtn[primary='true'] {
background-color: #465BEA;
}
QPushButton[primary='true']:pressed, #navBtn:pressed[primary='true'] {
background-color: #3049F4;
}
)");
}
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Setup setup;
setMainWindow(&setup);
return a.exec();
}