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.
 
 
 
 
 
 

306 lines
8.3 KiB

#include <cmath>
#include <fstream>
#include <iostream>
#include <thread>
#include <exception>
#include <QDateTime>
#include <QHBoxLayout>
#include <QMouseEvent>
#include <QVBoxLayout>
#include "common/params.h"
#include "common/timing.h"
#include "common/swaglog.h"
#include "common/watchdog.h"
#include "selfdrive/hardware/hw.h"
#include "home.hpp"
#include "paint.hpp"
#include "qt_window.hpp"
#include "widgets/drive_stats.hpp"
#include "widgets/setup.hpp"
#define BACKLIGHT_DT 0.25
#define BACKLIGHT_TS 2.00
#define BACKLIGHT_OFFROAD 50
// HomeWindow: the container for the offroad (OffroadHome) and onroad (GLWindow) UIs
HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) {
layout = new QStackedLayout();
layout->setStackingMode(QStackedLayout::StackAll);
// onroad UI
glWindow = new GLWindow(this);
layout->addWidget(glWindow);
// draw offroad UI on top of onroad UI
home = new OffroadHome();
layout->addWidget(home);
QObject::connect(glWindow, SIGNAL(offroadTransition(bool)), home, SLOT(setVisible(bool)));
QObject::connect(glWindow, SIGNAL(offroadTransition(bool)), this, SIGNAL(offroadTransition(bool)));
QObject::connect(glWindow, SIGNAL(screen_shutoff()), this, SIGNAL(closeSettings()));
QObject::connect(this, SIGNAL(openSettings()), home, SLOT(refresh()));
setLayout(layout);
}
void HomeWindow::mousePressEvent(QMouseEvent* e) {
UIState* ui_state = &glWindow->ui_state;
if (GLWindow::ui_state.scene.driver_view) {
Params().write_db_value("IsDriverViewEnabled", "0", 1);
return;
}
glWindow->wake();
// Settings button click
if (!ui_state->sidebar_collapsed && settings_btn.ptInRect(e->x(), e->y())) {
emit openSettings();
}
// Handle sidebar collapsing
if (ui_state->scene.started && (e->x() >= ui_state->viz_rect.x - bdr_s)) {
ui_state->sidebar_collapsed = !ui_state->sidebar_collapsed;
}
}
// OffroadHome: the offroad home page
OffroadHome::OffroadHome(QWidget* parent) : QWidget(parent) {
QVBoxLayout* main_layout = new QVBoxLayout();
main_layout->setContentsMargins(sbr_w + 50, 50, 50, 50);
// top header
QHBoxLayout* header_layout = new QHBoxLayout();
date = new QLabel();
date->setStyleSheet(R"(font-size: 55px;)");
header_layout->addWidget(date, 0, Qt::AlignTop | Qt::AlignLeft);
std::string brand = Params().read_db_bool("Passive") ? "dashcam" : "openpilot";
QLabel* version = new QLabel(QString::fromStdString(brand + " v" + Params().get("Version")));
version->setStyleSheet(R"(font-size: 55px;)");
header_layout->addWidget(version, 0, Qt::AlignTop | Qt::AlignRight);
main_layout->addLayout(header_layout);
alert_notification = new QPushButton();
QObject::connect(alert_notification, SIGNAL(released()), this, SLOT(openAlerts()));
main_layout->addWidget(alert_notification, 0, Qt::AlignTop | Qt::AlignRight);
// main content
main_layout->addSpacing(25);
center_layout = new QStackedLayout();
QHBoxLayout* statsAndSetup = new QHBoxLayout();
DriveStats* drive = new DriveStats;
drive->setFixedSize(800, 800);
statsAndSetup->addWidget(drive);
SetupWidget* setup = new SetupWidget;
//setup->setFixedSize(700, 700);
statsAndSetup->addWidget(setup);
QWidget* statsAndSetupWidget = new QWidget();
statsAndSetupWidget->setLayout(statsAndSetup);
center_layout->addWidget(statsAndSetupWidget);
alerts_widget = new OffroadAlert();
QObject::connect(alerts_widget, SIGNAL(closeAlerts()), this, SLOT(closeAlerts()));
center_layout->addWidget(alerts_widget);
center_layout->setAlignment(alerts_widget, Qt::AlignCenter);
main_layout->addLayout(center_layout, 1);
// set up refresh timer
timer = new QTimer(this);
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(refresh()));
refresh();
timer->start(10 * 1000);
setLayout(main_layout);
setStyleSheet(R"(
* {
color: white;
}
)");
}
void OffroadHome::openAlerts() {
center_layout->setCurrentIndex(1);
}
void OffroadHome::closeAlerts() {
center_layout->setCurrentIndex(0);
}
void OffroadHome::refresh() {
bool first_refresh = !date->text().size();
if (!isVisible() && !first_refresh) {
return;
}
date->setText(QDateTime::currentDateTime().toString("dddd, MMMM d"));
// update alerts
alerts_widget->refresh();
if (!alerts_widget->alerts.size() && !alerts_widget->updateAvailable) {
alert_notification->setVisible(false);
return;
}
if (alerts_widget->updateAvailable) {
alert_notification->setText("UPDATE");
} else {
int alerts = alerts_widget->alerts.size();
alert_notification->setText(QString::number(alerts) + " ALERT" + (alerts == 1 ? "" : "S"));
}
alert_notification->setVisible(true);
// Red background for alerts, blue for update available
QString style = QString(R"(
padding: 15px;
padding-left: 30px;
padding-right: 30px;
border: 1px solid;
border-radius: 5px;
font-size: 40px;
font-weight: 500;
background-color: #E22C2C;
)");
if (alerts_widget->updateAvailable) {
style.replace("#E22C2C", "#364DEF");
}
alert_notification->setStyleSheet(style);
}
// GLWindow: the onroad UI
static void handle_display_state(UIState* s, bool user_input) {
static int awake_timeout = 0;
awake_timeout = std::max(awake_timeout - 1, 0);
if (user_input || s->scene.ignition || s->scene.started) {
s->awake = true;
awake_timeout = 30 * UI_FREQ;
} else if (awake_timeout == 0) {
s->awake = false;
}
}
GLWindow::GLWindow(QWidget* parent) : QOpenGLWidget(parent) {
timer = new QTimer(this);
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(timerUpdate()));
backlight_timer = new QTimer(this);
QObject::connect(backlight_timer, SIGNAL(timeout()), this, SLOT(backlightUpdate()));
int result = read_param(&brightness_b, "BRIGHTNESS_B", true);
result += read_param(&brightness_m, "BRIGHTNESS_M", true);
if (result != 0) {
brightness_b = 10.0;
brightness_m = 0.1;
}
smooth_brightness = BACKLIGHT_OFFROAD;
}
GLWindow::~GLWindow() {
makeCurrent();
doneCurrent();
}
void GLWindow::initializeGL() {
initializeOpenGLFunctions();
std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl;
std::cout << "OpenGL vendor: " << glGetString(GL_VENDOR) << std::endl;
std::cout << "OpenGL renderer: " << glGetString(GL_RENDERER) << std::endl;
std::cout << "OpenGL language version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
ui_state.sound = &sound;
ui_state.fb_w = vwp_w;
ui_state.fb_h = vwp_h;
ui_init(&ui_state);
wake();
prev_draw_t = millis_since_boot();
timer->start(1000 / UI_FREQ);
backlight_timer->start(BACKLIGHT_DT * 1000);
}
void GLWindow::backlightUpdate() {
// Update brightness
float k = (BACKLIGHT_DT / BACKLIGHT_TS) / (1.0f + BACKLIGHT_DT / BACKLIGHT_TS);
float clipped_brightness = std::min(100.0f, (ui_state.scene.light_sensor * brightness_m) + brightness_b);
if (!ui_state.scene.started) {
clipped_brightness = BACKLIGHT_OFFROAD;
}
smooth_brightness = clipped_brightness * k + smooth_brightness * (1.0f - k);
int brightness = smooth_brightness;
if (!ui_state.awake) {
brightness = 0;
emit screen_shutoff();
}
if (brightness != last_brightness) {
std::thread{Hardware::set_brightness, brightness}.detach();
}
last_brightness = brightness;
}
void GLWindow::timerUpdate() {
// Connecting to visionIPC requires opengl to be current
if (!ui_state.vipc_client->connected){
makeCurrent();
}
if (ui_state.scene.started != onroad) {
onroad = ui_state.scene.started;
emit offroadTransition(!onroad);
// Change timeout to 0 when onroad, this will call timerUpdate continously.
// This puts visionIPC in charge of update frequency, reducing video latency
timer->start(onroad ? 0 : 1000 / UI_FREQ);
}
handle_display_state(&ui_state, false);
ui_update(&ui_state);
repaint();
watchdog_kick();
}
void GLWindow::resizeGL(int w, int h) {
std::cout << "resize " << w << "x" << h << std::endl;
}
void GLWindow::paintGL() {
if(GLWindow::ui_state.awake){
ui_draw(&ui_state);
double cur_draw_t = millis_since_boot();
double dt = cur_draw_t - prev_draw_t;
if (dt > 66 && onroad){
// warn on sub 15fps
LOGW("slow frame(%llu) time: %.2f", ui_state.sm->frame, dt);
}
prev_draw_t = cur_draw_t;
}
}
void GLWindow::wake() {
handle_display_state(&ui_state, true);
}