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.
 
 
 
 
 
 

277 lines
7.3 KiB

#include <cmath>
#include <fstream>
#include <iostream>
#include <thread>
#include <QDateTime>
#include <QHBoxLayout>
#include <QLayout>
#include <QMouseEvent>
#include <QStackedLayout>
#include <QVBoxLayout>
#include <QWidget>
#include "common/params.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
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);
QLabel* version = new QLabel(QString::fromStdString("openpilot v" + Params().get("Version")));
version->setStyleSheet(R"(font-size: 45px;)");
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(1000, 800);
statsAndSetup->addWidget(drive);
SetupWidget* setup = new SetupWidget;
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"(background-color: none;)");
}
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) {
// There is a new release
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: bold;
background-color: #E22C2C;
)");
if (alerts_widget->updateAvailable) {
style.replace("#E22C2C", "#364DEF");
}
alert_notification->setStyleSheet(style);
}
HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) {
layout = new QGridLayout;
layout->setMargin(0);
// onroad UI
glWindow = new GLWindow(this);
layout->addWidget(glWindow, 0, 0);
// draw offroad UI on top of onroad UI
home = new OffroadHome();
layout->addWidget(home, 0, 0);
QObject::connect(glWindow, SIGNAL(offroadTransition(bool)), this, SLOT(setVisibility(bool)));
QObject::connect(this, SIGNAL(openSettings()), home, SLOT(refresh()));
setLayout(layout);
setStyleSheet(R"(
* {
color: white;
}
)");
}
void HomeWindow::setVisibility(bool offroad) {
home->setVisible(offroad);
}
void HomeWindow::mousePressEvent(QMouseEvent* e) {
UIState* ui_state = &glWindow->ui_state;
glWindow->wake();
// Settings button click
if (!ui_state->scene.sidebar_collapsed && settings_btn.ptInRect(e->x(), e->y())) {
emit openSettings();
}
// Vision click
if (ui_state->started && (e->x() >= ui_state->scene.viz_rect.x - bdr_s)) {
ui_state->scene.sidebar_collapsed = !ui_state->scene.sidebar_collapsed;
}
}
static void handle_display_state(UIState* s, bool user_input) {
static int awake_timeout = 0; // Somehow this only gets called on program start
awake_timeout = std::max(awake_timeout - 1, 0);
if (user_input || s->ignition || s->started) {
s->awake = true;
awake_timeout = 30 * UI_FREQ;
} else if (awake_timeout == 0) {
s->awake = false;
}
}
static void set_backlight(int brightness) {
std::ofstream brightness_control("/sys/class/backlight/panel0-backlight/brightness");
if (brightness_control.is_open()) {
brightness_control << brightness << "\n";
brightness_control.close();
}
}
GLWindow::GLWindow(QWidget* parent) : QOpenGLWidget(parent) {
timer = new QTimer(this);
timer->start(1000 / UI_FREQ);
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 = 200.0;
brightness_m = 10.0;
}
smooth_brightness = 512;
}
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_init(&ui_state);
wake();
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(1023.0f, (ui_state.light_sensor * brightness_m) + brightness_b);
smooth_brightness = clipped_brightness * k + smooth_brightness * (1.0f - k);
int brightness = smooth_brightness;
if (!ui_state.awake) {
brightness = 0;
}
std::thread{set_backlight, brightness}.detach();
}
void GLWindow::timerUpdate() {
if (ui_state.started != onroad) {
onroad = ui_state.started;
emit offroadTransition(!onroad);
}
handle_display_state(&ui_state, false);
ui_update(&ui_state);
repaint();
}
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);
}
}
void GLWindow::wake() {
handle_display_state(&ui_state, true);
}
FramebufferState* framebuffer_init(const char* name, int32_t layer, int alpha,
int *out_w, int *out_h) {
*out_w = vwp_w;
*out_h = vwp_h;
return (FramebufferState*)1; // not null
}