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.
 
 
 
 
 
 

205 lines
6.5 KiB

#include "selfdrive/ui/qt/onroad.h"
#include <iostream>
#include <QDebug>
#include "selfdrive/common/swaglog.h"
#include "selfdrive/common/timing.h"
#include "selfdrive/ui/paint.h"
#include "selfdrive/ui/qt/util.h"
#ifdef ENABLE_MAPS
#include "selfdrive/ui/qt/maps/map.h"
#endif
OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) {
main_layout = new QStackedLayout(this);
main_layout->setStackingMode(QStackedLayout::StackAll);
// old UI on bottom
nvg = new NvgWindow(this);
QObject::connect(this, &OnroadWindow::update, nvg, &NvgWindow::update);
QWidget * split_wrapper = new QWidget;
split = new QHBoxLayout(split_wrapper);
split->setContentsMargins(0, 0, 0, 0);
split->setSpacing(0);
split->addWidget(nvg);
main_layout->addWidget(split_wrapper);
alerts = new OnroadAlerts(this);
alerts->setAttribute(Qt::WA_TransparentForMouseEvents, true);
QObject::connect(this, &OnroadWindow::update, alerts, &OnroadAlerts::updateState);
QObject::connect(this, &OnroadWindow::offroadTransitionSignal, alerts, &OnroadAlerts::offroadTransition);
QObject::connect(this, &OnroadWindow::offroadTransitionSignal, this, &OnroadWindow::offroadTransition);
main_layout->addWidget(alerts);
// setup stacking order
alerts->raise();
setAttribute(Qt::WA_OpaquePaintEvent);
}
void OnroadWindow::offroadTransition(bool offroad) {
#ifdef ENABLE_MAPS
if (!offroad) {
QString token = QString::fromStdString(Params().get("MapboxToken"));
if (map == nullptr && !token.isEmpty()) {
QMapboxGLSettings settings;
if (!Hardware::PC()) {
settings.setCacheDatabasePath("/data/mbgl-cache.db");
}
settings.setCacheDatabaseMaximumSize(20 * 1024 * 1024);
settings.setAccessToken(token.trimmed());
MapWindow * m = new MapWindow(settings);
QObject::connect(this, &OnroadWindow::offroadTransitionSignal, m, &MapWindow::offroadTransition);
split->addWidget(m);
map = m;
}
}
#endif
}
// ***** onroad widgets *****
void OnroadAlerts::updateState(const UIState &s) {
SubMaster &sm = *(s.sm);
if (sm["deviceState"].getDeviceState().getStarted()) {
if (sm.updated("controlsState")) {
const cereal::ControlsState::Reader &cs = sm["controlsState"].getControlsState();
updateAlert({QString::fromStdString(cs.getAlertText1()),
QString::fromStdString(cs.getAlertText2()),
QString::fromStdString(cs.getAlertType()),
cs.getAlertSize(), cs.getAlertSound()});
} else if ((sm.frame - s.scene.started_frame) > 5 * UI_FREQ) {
// Handle controls timeout
if (sm.rcv_frame("controlsState") < s.scene.started_frame) {
// car is started, but controlsState hasn't been seen at all
updateAlert(CONTROLS_WAITING_ALERT);
} else if ((nanos_since_boot() - sm.rcv_time("controlsState")) / 1e9 > CONTROLS_TIMEOUT) {
// car is started, but controls is lagging or died
updateAlert(CONTROLS_UNRESPONSIVE_ALERT);
// TODO: clean this up once Qt handles the border
QUIState::ui_state.status = STATUS_ALERT;
}
}
}
bg = bg_colors[s.status];
}
void OnroadAlerts::offroadTransition(bool offroad) {
updateAlert({});
}
void OnroadAlerts::updateAlert(Alert a) {
if (!alert.equal(a)) {
alert = a;
update();
}
}
void OnroadAlerts::paintEvent(QPaintEvent *event) {
if (alert.size == cereal::ControlsState::AlertSize::NONE) {
return;
}
static std::map<cereal::ControlsState::AlertSize, const int> alert_sizes = {
{cereal::ControlsState::AlertSize::SMALL, 271},
{cereal::ControlsState::AlertSize::MID, 420},
{cereal::ControlsState::AlertSize::FULL, height()},
};
int h = alert_sizes[alert.size];
QRect r = QRect(0, height() - h, width(), h);
QPainter p(this);
// draw background + gradient
p.setPen(Qt::NoPen);
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
p.setBrush(QBrush(bg));
p.drawRect(r);
QLinearGradient g(0, r.y(), 0, r.bottom());
g.setColorAt(0, QColor::fromRgbF(0, 0, 0, 0.05));
g.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0.35));
p.setCompositionMode(QPainter::CompositionMode_DestinationOver);
p.setBrush(QBrush(g));
p.fillRect(r, g);
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
// remove bottom border
r = QRect(0, height() - h, width(), h - 30);
// text
const QPoint c = r.center();
p.setPen(QColor(0xff, 0xff, 0xff));
p.setRenderHint(QPainter::TextAntialiasing);
if (alert.size == cereal::ControlsState::AlertSize::SMALL) {
configFont(p, "Open Sans", 74, "SemiBold");
p.drawText(r, Qt::AlignCenter, alert.text1);
} else if (alert.size == cereal::ControlsState::AlertSize::MID) {
configFont(p, "Open Sans", 88, "Bold");
p.drawText(QRect(0, c.y() - 125, width(), 150), Qt::AlignHCenter | Qt::AlignTop, alert.text1);
configFont(p, "Open Sans", 66, "Regular");
p.drawText(QRect(0, c.y() + 21, width(), 90), Qt::AlignHCenter, alert.text2);
} else if (alert.size == cereal::ControlsState::AlertSize::FULL) {
bool l = alert.text1.length() > 15;
configFont(p, "Open Sans", l ? 132 : 177, "Bold");
p.drawText(QRect(0, r.y() + (l ? 240 : 270), width(), 600), Qt::AlignHCenter | Qt::TextWordWrap, alert.text1);
configFont(p, "Open Sans", 88, "Regular");
p.drawText(QRect(0, r.height() - (l ? 361 : 420), width(), 300), Qt::AlignHCenter | Qt::TextWordWrap, alert.text2);
}
}
NvgWindow::NvgWindow(QWidget *parent) : QOpenGLWidget(parent) {
setAttribute(Qt::WA_OpaquePaintEvent);
}
NvgWindow::~NvgWindow() {
makeCurrent();
doneCurrent();
}
void NvgWindow::initializeGL() {
initializeOpenGLFunctions();
qInfo() << "OpenGL version:" << QString((const char*)glGetString(GL_VERSION));
qInfo() << "OpenGL vendor:" << QString((const char*)glGetString(GL_VENDOR));
qInfo() << "OpenGL renderer:" << QString((const char*)glGetString(GL_RENDERER));
qInfo() << "OpenGL language version:" << QString((const char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
ui_nvg_init(&QUIState::ui_state);
prev_draw_t = millis_since_boot();
}
void NvgWindow::update(const UIState &s) {
// Connecting to visionIPC requires opengl to be current
if (s.vipc_client->connected) {
makeCurrent();
}
repaint();
}
void NvgWindow::resizeGL(int w, int h) {
ui_resize(&QUIState::ui_state, w, h);
}
void NvgWindow::paintGL() {
ui_draw(&QUIState::ui_state, width(), height());
double cur_draw_t = millis_since_boot();
double dt = cur_draw_t - prev_draw_t;
if (dt > 66) {
// warn on sub 15fps
LOGW("slow frame time: %.2f", dt);
}
prev_draw_t = cur_draw_t;
}