openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

404 lines
12 KiB

#include <QDebug>
#include <QHBoxLayout>
#include <QLabel>
#include <QPixmap>
#include <QPushButton>
#include <QLineEdit>
#include <QRandomGenerator>
#include <QtConcurrent>
#include "common/params.h"
#include "networking.hpp"
#include "util.h"
void clearLayout(QLayout* layout) {
while (QLayoutItem* item = layout->takeAt(0)) {
if (QWidget* widget = item->widget()) {
widget->deleteLater();
}
if (QLayout* childLayout = item->layout()) {
clearLayout(childLayout);
}
delete item;
}
}
QWidget* layoutToWidget(QLayout* l, QWidget* parent){
QWidget* q = new QWidget(parent);
q->setLayout(l);
return q;
}
// https://stackoverflow.com/questions/478898/how-do-i-execute-a-command-and-get-the-output-of-the-command-within-c-using-po
std::string exec(const char* cmd) {
std::array<char, 128> buffer;
std::string result;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
if (!pipe) {
throw std::runtime_error("popen() failed!");
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
return result;
}
// Networking functions
Networking::Networking(QWidget* parent, bool show_advanced) : QWidget(parent), show_advanced(show_advanced){
s = new QStackedLayout;
QLabel* warning = new QLabel("Network manager is inactive!");
warning->setStyleSheet(R"(font-size: 65px;)");
s->addWidget(warning);
setLayout(s);
QTimer* timer = new QTimer(this);
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(refresh()));
timer->start(5000);
attemptInitialization();
}
void Networking::attemptInitialization(){
// Checks if network manager is active
try {
wifi = new WifiManager(this);
} catch (std::exception &e) {
return;
}
connect(wifi, SIGNAL(wrongPassword(QString)), this, SLOT(wrongPassword(QString)));
QVBoxLayout* vlayout = new QVBoxLayout;
if (show_advanced) {
QPushButton* advancedSettings = new QPushButton("Advanced");
advancedSettings->setStyleSheet(R"(margin-right: 30px)");
advancedSettings->setFixedSize(350, 100);
connect(advancedSettings, &QPushButton::released, [=](){s->setCurrentWidget(an);});
vlayout->addSpacing(10);
vlayout->addWidget(advancedSettings, 0, Qt::AlignRight);
vlayout->addSpacing(10);
}
wifiWidget = new WifiUI(0, 5, wifi);
connect(wifiWidget, SIGNAL(connectToNetwork(Network)), this, SLOT(connectToNetwork(Network)));
vlayout->addWidget(wifiWidget, 1);
wifiScreen = layoutToWidget(vlayout, this);
s->addWidget(wifiScreen);
an = new AdvancedNetworking(this, wifi);
connect(an, &AdvancedNetworking::backPress, [=](){s->setCurrentWidget(wifiScreen);});
s->addWidget(an);
setStyleSheet(R"(
QPushButton {
font-size: 50px;
margin: 0px;
padding: 15px;
border-width: 0;
border-radius: 30px;
color: #dddddd;
background-color: #444444;
}
QPushButton:disabled {
color: #777777;
background-color: #222222;
}
)");
s->setCurrentWidget(wifiScreen);
ui_setup_complete = true;
}
void Networking::refresh(){
if (!this->isVisible()) {
return;
}
if (!ui_setup_complete) {
attemptInitialization();
if (!ui_setup_complete) {
return;
}
}
wifiWidget->refresh();
an->refresh();
}
void Networking::connectToNetwork(Network n) {
if (n.security_type == SecurityType::OPEN) {
wifi->connect(n);
} else if (n.security_type == SecurityType::WPA) {
QString pass = InputDialog::getText("Enter password for \"" + n.ssid + "\"");
wifi->connect(n, pass);
}
}
void Networking::wrongPassword(QString ssid) {
return; // TODO: add this back
/*
for (Network n : wifi->seen_networks) {
if (n.ssid == ssid) {
inputField->setPromptText("Wrong password for \"" + n.ssid +"\"");
s->setCurrentIndex(0);
emit openKeyboard();
return;
}
}
*/
}
QFrame* hline(QWidget* parent = 0){
QFrame* line = new QFrame(parent);
line->setFrameShape(QFrame::StyledPanel);
line->setStyleSheet("margin-left: 40px; margin-right: 40px; border-width: 1px; border-bottom-style: solid; border-color: gray;");
line->setFixedHeight(2);
return line;
}
// AdvancedNetworking functions
AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWidget(parent), wifi(wifi){
s = new QStackedLayout; // mainPage, SSH settings
QVBoxLayout* vlayout = new QVBoxLayout;
// Back button
QHBoxLayout* backLayout = new QHBoxLayout;
QPushButton* back = new QPushButton("Back");
back->setFixedSize(500, 100);
connect(back, &QPushButton::released, [=](){emit backPress();});
backLayout->addWidget(back, 0, Qt::AlignLeft);
vlayout->addWidget(layoutToWidget(backLayout, this), 0, Qt::AlignLeft);
// Enable tethering layout
QHBoxLayout* tetheringToggleLayout = new QHBoxLayout;
tetheringToggleLayout->addWidget(new QLabel("Enable tethering"));
Toggle* toggle_switch = new Toggle;
toggle_switch->setFixedSize(150, 100);
tetheringToggleLayout->addWidget(toggle_switch);
tetheringToggleLayout->addSpacing(40);
if (wifi->tetheringEnabled()) {
toggle_switch->togglePosition();
}
QObject::connect(toggle_switch, SIGNAL(stateChanged(int)), this, SLOT(toggleTethering(int)));
vlayout->addWidget(layoutToWidget(tetheringToggleLayout, this), 0);
vlayout->addWidget(hline(), 0);
// Change tethering password
QHBoxLayout *tetheringPassword = new QHBoxLayout;
tetheringPassword->addWidget(new QLabel("Edit tethering password"), 1);
editPasswordButton = new QPushButton("EDIT");
editPasswordButton->setFixedWidth(500);
connect(editPasswordButton, &QPushButton::released, [=](){
QString pass = InputDialog::getText("Enter new tethering password");
if (pass.size()) {
wifi->changeTetheringPassword(pass);
}
});
tetheringPassword->addWidget(editPasswordButton, 1, Qt::AlignRight);
vlayout->addWidget(layoutToWidget(tetheringPassword, this), 0);
vlayout->addWidget(hline(), 0);
// IP adress
QHBoxLayout* IPlayout = new QHBoxLayout;
IPlayout->addWidget(new QLabel("IP address"), 0);
ipLabel = new QLabel(wifi->ipv4_address);
ipLabel->setStyleSheet("color: #aaaaaa");
IPlayout->addWidget(ipLabel, 0, Qt::AlignRight);
vlayout->addWidget(layoutToWidget(IPlayout, this), 0);
vlayout->addWidget(hline(), 0);
// Enable SSH
QHBoxLayout* enableSSHLayout = new QHBoxLayout(this);
enableSSHLayout->addWidget(new QLabel("Enable SSH", this));
toggle_switch_SSH = new Toggle(this);
toggle_switch_SSH->setFixedSize(150, 100);
if (isSSHEnabled()) {
toggle_switch_SSH->togglePosition();
}
QObject::connect(toggle_switch_SSH, SIGNAL(stateChanged(int)), this, SLOT(toggleSSH(int)));
enableSSHLayout->addWidget(toggle_switch_SSH);
vlayout->addWidget(layoutToWidget(enableSSHLayout, this));
vlayout->addWidget(hline(), 0);
// SSH keys
QHBoxLayout* authSSHLayout = new QHBoxLayout(this);
authSSHLayout->addWidget(new QLabel("SSH keys", this));
QPushButton* editAuthSSHButton = new QPushButton("EDIT", this);
editAuthSSHButton->setFixedWidth(500);
connect(editAuthSSHButton, &QPushButton::released, [=](){s->setCurrentWidget(ssh);});
authSSHLayout->addWidget(editAuthSSHButton);
vlayout->addWidget(layoutToWidget(authSSHLayout, this));
vlayout->addSpacing(50);
// //Disconnect or delete connections
// QHBoxLayout* dangerZone = new QHBoxLayout(this);
// QPushButton* disconnect = new QPushButton("Disconnect from WiFi", this);
// dangerZone->addWidget(disconnect);
// QPushButton* deleteAll = new QPushButton("DELETE ALL NETWORKS", this);
// dangerZone->addWidget(deleteAll);
// vlayout->addWidget(layoutToWidget(dangerZone, this));
// vlayout to widget
QWidget* settingsWidget = layoutToWidget(vlayout, this);
settingsWidget->setStyleSheet("margin-left: 40px; margin-right: 40px;");
s->addWidget(settingsWidget);
ssh = new SSH;
connect(ssh, &SSH::closeSSHSettings, [=](){s->setCurrentWidget(settingsWidget);});
s->addWidget(ssh);
setLayout(s);
}
bool AdvancedNetworking::isSSHEnabled(){
QString response = QString::fromStdString(exec("systemctl is-active ssh"));
return response.startsWith("active");
}
void AdvancedNetworking::refresh(){
ipLabel->setText(wifi->ipv4_address);
// Don't refresh while changing SSH state
if(!toggle_switch_SSH->getEnabled()){
return;
}
if (toggle_switch_SSH->on != isSSHEnabled()) {
toggle_switch_SSH->togglePosition();
}
// Qt can be lazy
repaint();
}
void AdvancedNetworking::toggleTethering(int enable) {
if (enable) {
wifi->enableTethering();
} else {
wifi->disableTethering();
}
editPasswordButton->setEnabled(!enable);
}
void enableSSH(Toggle* toggle_switch_SSH){
Params().write_db_value("SshEnabled", "1");
toggle_switch_SSH->setEnabled(true);
}
void disableSSH(Toggle* toggle_switch_SSH){
Params().write_db_value("SshEnabled", "0");
toggle_switch_SSH->setEnabled(true);
}
void AdvancedNetworking::toggleSSH(int enable) {
toggle_switch_SSH->setEnabled(false);
if (enable) {
QtConcurrent::run(enableSSH, toggle_switch_SSH);
} else {
QtConcurrent::run(disableSSH, toggle_switch_SSH);
}
}
// WifiUI functions
WifiUI::WifiUI(QWidget *parent, int page_length, WifiManager* wifi) : QWidget(parent), networks_per_page(page_length), wifi(wifi) {
vlayout = new QVBoxLayout;
// Scan on startup
QLabel *scanning = new QLabel("Scanning for networks");
scanning->setStyleSheet(R"(font-size: 65px;)");
vlayout->addWidget(scanning, 0, Qt::AlignCenter);
vlayout->setSpacing(25);
setLayout(vlayout);
page = 0;
}
void WifiUI::refresh() {
wifi->request_scan();
wifi->refreshNetworks();
clearLayout(vlayout);
connectButtons = new QButtonGroup(this); // TODO check if this is a leak
QObject::connect(connectButtons, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(handleButton(QAbstractButton*)));
int i = 0;
int countWidgets = 0;
for (Network &network : wifi->seen_networks) {
QHBoxLayout *hlayout = new QHBoxLayout;
if (page * networks_per_page <= i && i < (page + 1) * networks_per_page) {
// SSID
hlayout->addSpacing(50);
QString ssid = QString::fromUtf8(network.ssid);
if(ssid.length() > 20){
ssid = ssid.left(20 - 3) + "";
}
QLabel *ssid_label = new QLabel(ssid);
ssid_label->setStyleSheet(R"(
font-size: 55px;
)");
ssid_label->setFixedWidth(this->width()*0.5);
hlayout->addWidget(ssid_label, 0, Qt::AlignLeft);
// TODO: don't use images for this
// strength indicator
unsigned int strength_scale = network.strength / 17;
QPixmap pix("../assets/images/network_" + QString::number(strength_scale) + ".png");
QLabel *icon = new QLabel();
icon->setPixmap(pix.scaledToWidth(100, Qt::SmoothTransformation));
icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
hlayout->addWidget(icon, 0, Qt::AlignRight);
// connect button
QPushButton* btn = new QPushButton(network.security_type == SecurityType::UNSUPPORTED ? "Unsupported" : (network.connected == ConnectedType::CONNECTED ? "Connected" : (network.connected == ConnectedType::CONNECTING ? "Connecting" : "Connect")));
btn->setDisabled(network.connected == ConnectedType::CONNECTED || network.connected == ConnectedType::CONNECTING || network.security_type == SecurityType::UNSUPPORTED);
btn->setFixedWidth(350);
hlayout->addWidget(btn, 0, Qt::AlignRight);
connectButtons->addButton(btn, i);
vlayout->addLayout(hlayout, 1);
// Don't add the last horizontal line
if (page * networks_per_page <= i+1 && i+1 < (page + 1) * networks_per_page && i+1 < wifi->seen_networks.size()) {
vlayout->addWidget(hline(), 0);
}
countWidgets++;
}
i++;
}
vlayout->addStretch(3);
// Setup buttons for pagination
QHBoxLayout *prev_next_buttons = new QHBoxLayout;
QPushButton* prev = new QPushButton("Previous");
prev->setEnabled(page);
QObject::connect(prev, SIGNAL(released()), this, SLOT(prevPage()));
prev_next_buttons->addWidget(prev);
QPushButton* next = new QPushButton("Next");
next->setEnabled(wifi->seen_networks.size() > (page + 1) * networks_per_page);
QObject::connect(next, SIGNAL(released()), this, SLOT(nextPage()));
prev_next_buttons->addWidget(next);
vlayout->addLayout(prev_next_buttons, 2);
}
void WifiUI::handleButton(QAbstractButton* button) {
QPushButton* btn = static_cast<QPushButton*>(button);
Network n = wifi->seen_networks[connectButtons->id(btn)];
emit connectToNetwork(n);
}
void WifiUI::prevPage() {
page--;
refresh();
}
void WifiUI::nextPage() {
page++;
refresh();
}