UI: refactor GLWindow (#20764)

pull/20765/head
Adeeb Shihadeh 2021-04-29 11:18:59 -07:00 committed by GitHub
parent 0d10f9c4ad
commit 140e6248e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 359 additions and 311 deletions

View File

@ -27,7 +27,7 @@ qt_env.Program("qt/text", ["qt/text.cc"], LIBS=qt_libs)
qt_env.Program("qt/spinner", ["qt/spinner.cc"], LIBS=base_libs)
# build main UI
qt_src = ["main.cc", "ui.cc", "paint.cc", "sidebar.cc",
qt_src = ["main.cc", "ui.cc", "paint.cc", "sidebar.cc", "qt/onroad.cc",
"qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc",
"qt/offroad/onboarding.cc", "#phonelibs/nanovg/nanovg.c"]

View File

@ -1,9 +1,19 @@
#include "ui.hpp"
#include <assert.h>
#include <algorithm>
#include "ui.hpp"
#ifdef __APPLE__
#include <OpenGL/gl3.h>
#define NANOVG_GL3_IMPLEMENTATION
#define nvgCreate nvgCreateGL3
#else
#include <GLES3/gl3.h>
#define NANOVG_GLES3_IMPLEMENTATION
#define nvgCreate nvgCreateGLES3
#endif
#include "common/util.h"
#include "common/timing.h"
#include <algorithm>
#define NANOVG_GLES3_IMPLEMENTATION
#include "nanovg_gl.h"

View File

@ -1,4 +1,5 @@
#pragma once
#include "ui.hpp"
void ui_draw(UIState *s);

View File

@ -1,9 +1,3 @@
#include <cmath>
#include <fstream>
#include <iostream>
#include <thread>
#include <exception>
#include <QDateTime>
#include <QHBoxLayout>
#include <QMouseEvent>
@ -13,59 +7,46 @@
#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: the container for the offroad and onroad 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
onroad = new OnroadWindow(this);
layout->addWidget(onroad);
QObject::connect(this, &HomeWindow::update, onroad, &OnroadWindow::update);
QObject::connect(this, &HomeWindow::displayPowerChanged, onroad, &OnroadWindow::setEnabled);
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()));
QObject::connect(this, &HomeWindow::openSettings, home, &OffroadHome::refresh);
QObject::connect(this, &HomeWindow::offroadTransition, home, &OffroadHome::setVisible);
setLayout(layout);
}
void HomeWindow::mousePressEvent(QMouseEvent* e) {
UIState* ui_state = &glWindow->ui_state;
if (GLWindow::ui_state.scene.driver_view) {
// TODO: make a nice driver view widget
if (QUIState::ui_state.scene.driver_view) {
Params().putBool("IsDriverViewEnabled", false);
GLWindow::ui_state.scene.driver_view = false;
QUIState::ui_state.scene.driver_view = false;
return;
}
glWindow->wake();
// Settings button click
if (!ui_state->sidebar_collapsed && settings_btn.ptInRect(e->x(), e->y())) {
if (!QUIState::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;
if (QUIState::ui_state.scene.started && (e->x() >= QUIState::ui_state.viz_rect.x - bdr_s)) {
QUIState::ui_state.sidebar_collapsed = !QUIState::ui_state.sidebar_collapsed;
}
}
@ -189,139 +170,3 @@ void OffroadHome::refresh() {
}
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);
constexpr float accel_samples = 5*UI_FREQ;
static float accel_prev = 0., gyro_prev = 0.;
bool should_wake = s->scene.started || s->scene.ignition || user_input;
if (!should_wake) {
// tap detection while display is off
bool accel_trigger = abs(s->scene.accel_sensor - accel_prev) > 0.2;
bool gyro_trigger = abs(s->scene.gyro_sensor - gyro_prev) > 0.15;
should_wake = accel_trigger && gyro_trigger;
gyro_prev = s->scene.gyro_sensor;
accel_prev = (accel_prev * (accel_samples - 1) + s->scene.accel_sensor) / accel_samples;
}
if (should_wake) {
awake_timeout = 30 * UI_FREQ;
} else if (awake_timeout > 0) {
should_wake = true;
}
// handle state transition
if (s->awake != should_wake) {
s->awake = should_wake;
Hardware::set_display_power(s->awake);
LOGD("setting display power %d", s->awake);
}
}
GLWindow::GLWindow(QWidget* parent) : brightness_filter(BACKLIGHT_OFFROAD, BACKLIGHT_TS, BACKLIGHT_DT), 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()));
brightness_b = Params(true).get<float>("BRIGHTNESS_B").value_or(10.0);
brightness_m = Params(true).get<float>("BRIGHTNESS_M").value_or(0.1);
}
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 clipped_brightness = std::min(100.0f, (ui_state.scene.light_sensor * brightness_m) + brightness_b);
if (!ui_state.scene.started) {
clipped_brightness = BACKLIGHT_OFFROAD;
}
int brightness = brightness_filter.update(clipped_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);
// scale volume with speed
sound.volume = util::map_val(ui_state.scene.car_state.getVEgo(), 0.f, 20.f,
Hardware::MIN_VOLUME, Hardware::MAX_VOLUME);
ui_update(&ui_state);
if(GLWindow::ui_state.awake){
repaint();
}
watchdog_kick();
}
void GLWindow::resizeGL(int w, int h) {
std::cout << "resize " << w << "x" << h << std::endl;
}
void GLWindow::paintGL() {
ui_draw(&ui_state);
double cur_draw_t = millis_since_boot();
double dt = cur_draw_t - prev_draw_t;
if (dt > 66 && onroad && !ui_state.scene.driver_view) {
// 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);
}

View File

@ -1,61 +1,15 @@
#pragma once
#include <QLabel>
#include <QOpenGLFunctions>
#include <QOpenGLWidget>
#include <QPushButton>
#include <QStackedLayout>
#include <QStackedWidget>
#include <QTimer>
#include <QWidget>
#include "sound.hpp"
#include "onroad.hpp"
#include "ui/ui.hpp"
#include "common/util.h"
#include "widgets/offroad_alerts.hpp"
// container window for onroad NVG UI
class GLWindow : public QOpenGLWidget, protected QOpenGLFunctions {
Q_OBJECT
public:
using QOpenGLWidget::QOpenGLWidget;
explicit GLWindow(QWidget* parent = 0);
void wake();
~GLWindow();
inline static UIState ui_state = {0};
signals:
void offroadTransition(bool offroad);
void screen_shutoff();
protected:
void initializeGL() override;
void resizeGL(int w, int h) override;
void paintGL() override;
private:
QTimer* timer;
QTimer* backlight_timer;
Sound sound;
bool onroad = true;
double prev_draw_t = 0;
// TODO: make a nice abstraction to handle embedded device stuff
float brightness_b = 0;
float brightness_m = 0;
float last_brightness = 0;
FirstOrderFilter brightness_filter;
public slots:
void timerUpdate();
void backlightUpdate();
};
// offroad home screen
class OffroadHome : public QWidget {
Q_OBJECT
@ -81,17 +35,21 @@ class HomeWindow : public QWidget {
public:
explicit HomeWindow(QWidget* parent = 0);
GLWindow* glWindow;
signals:
void openSettings();
void closeSettings();
// forwarded signals
void displayPowerChanged(bool on);
void offroadTransition(bool offroad);
void update(const UIState &s);
protected:
void mousePressEvent(QMouseEvent* e) override;
private:
OffroadHome* home;
QStackedLayout* layout;
OffroadHome *home;
OnroadWindow *onroad;
QStackedLayout *layout;
};

View File

@ -16,8 +16,7 @@
#include "common/params.h"
#include "common/util.h"
#include "selfdrive/hardware/hw.h"
#include "home.hpp"
#include "ui.hpp"
TogglesPanel::TogglesPanel(QWidget *parent) : QWidget(parent) {
QVBoxLayout *toggles_list = new QVBoxLayout();
@ -116,7 +115,7 @@ DevicePanel::DevicePanel(QWidget* parent) : QWidget(parent) {
"Preview the driver facing camera to help optimize device mounting position for best driver monitoring experience. (vehicle must be off)",
[=]() {
Params().putBool("IsDriverViewEnabled", true);
GLWindow::ui_state.scene.driver_view = true;
QUIState::ui_state.scene.driver_view = true;
}, "", this));
QString resetCalibDesc = "openpilot requires the device to be mounted within 4° left or right and within 5° up or down. openpilot is continuously calibrating, resetting is rarely required.";

View File

@ -0,0 +1,57 @@
#include <iostream>
#include "common/timing.h"
#include "common/swaglog.h"
#include "onroad.hpp"
#include "paint.hpp"
OnroadWindow::~OnroadWindow() {
makeCurrent();
doneCurrent();
}
void OnroadWindow::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;
enabled = true;
ui_nvg_init(&QUIState::ui_state);
prev_draw_t = millis_since_boot();
}
void OnroadWindow::setEnabled(bool on) {
enabled = on;
}
void OnroadWindow::update(const UIState &s) {
// Connecting to visionIPC requires opengl to be current
if (s.vipc_client->connected){
makeCurrent();
}
// TODO: will hide do this?
if(enabled) {
repaint();
}
}
void OnroadWindow::resizeGL(int w, int h) {
std::cout << "resize " << w << "x" << h << std::endl;
}
void OnroadWindow::paintGL() {
ui_draw(&QUIState::ui_state);
double cur_draw_t = millis_since_boot();
double dt = cur_draw_t - prev_draw_t;
// TODO: check if onroad
if (dt > 66 && QUIState::ui_state.scene.started && !QUIState::ui_state.scene.driver_view) {
// warn on sub 15fps
LOGW("slow frame time: %.2f", dt);
}
prev_draw_t = cur_draw_t;
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <QOpenGLFunctions>
#include <QOpenGLWidget>
#include <QTimer>
#include "ui/ui.hpp"
// container window for the NVG UI
class OnroadWindow : public QOpenGLWidget, protected QOpenGLFunctions {
Q_OBJECT
public:
using QOpenGLWidget::QOpenGLWidget;
explicit OnroadWindow(QWidget* parent = 0) : QOpenGLWidget(parent) {};
~OnroadWindow();
protected:
void paintGL() override;
void initializeGL() override;
void resizeGL(int w, int h) override;
private:
bool enabled;
double prev_draw_t = 0;
public slots:
void setEnabled(bool on);
void update(const UIState &s);
};

View File

@ -1,12 +1,13 @@
#include "request_repeater.hpp"
RequestRepeater::RequestRepeater(QObject *parent, QString requestURL, const QString &cache_key, int period_seconds, bool disableWithScreen) :
HttpRequest(parent, requestURL, cache_key), disableWithScreen(disableWithScreen) {
QTimer* timer = new QTimer(this);
RequestRepeater::RequestRepeater(QObject *parent, QString requestURL, const QString &cacheKey,
int period) : HttpRequest(parent, requestURL, cacheKey) {
timer = new QTimer(this);
timer->setTimerType(Qt::VeryCoarseTimer);
QObject::connect(timer, &QTimer::timeout, [=](){
if (!GLWindow::ui_state.scene.started && reply == NULL && (GLWindow::ui_state.awake || !disableWithScreen)) {
if (!QUIState::ui_state.scene.started && QUIState::ui_state.awake && reply == NULL) {
sendRequest(requestURL);
}
});
timer->start(period_seconds * 1000);
timer->start(period * 1000);
}

View File

@ -1,9 +1,10 @@
#include "api.hpp"
#include "home.hpp"
#include "ui.hpp"
class RequestRepeater : public HttpRequest {
public:
RequestRepeater(QObject *parent, QString requestURL, const QString &cache_key = "", int period_seconds = 0, bool disableWithScreen = true);
bool disableWithScreen;
RequestRepeater(QObject *parent, QString requestURL, const QString &cacheKey = "", int period = 0);
private:
QTimer *timer;
};

View File

@ -6,18 +6,6 @@
typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert;
static std::map<AudibleAlert, std::pair<const char *, int>> sound_map {
// AudibleAlert, (file path, loop count)
{AudibleAlert::CHIME_DISENGAGE, {"../assets/sounds/disengaged.wav", 0}},
{AudibleAlert::CHIME_ENGAGE, {"../assets/sounds/engaged.wav", 0}},
{AudibleAlert::CHIME_WARNING1, {"../assets/sounds/warning_1.wav", 0}},
{AudibleAlert::CHIME_WARNING2, {"../assets/sounds/warning_2.wav", 0}},
{AudibleAlert::CHIME_WARNING2_REPEAT, {"../assets/sounds/warning_2.wav", -1}},
{AudibleAlert::CHIME_WARNING_REPEAT, {"../assets/sounds/warning_repeat.wav", -1}},
{AudibleAlert::CHIME_ERROR, {"../assets/sounds/error.wav", 0}},
{AudibleAlert::CHIME_PROMPT, {"../assets/sounds/error.wav", 0}}
};
class Sound {
public:
Sound();
@ -26,5 +14,17 @@ public:
float volume = 0;
private:
std::map<AudibleAlert, std::pair<QString, int>> sound_map {
// AudibleAlert, (file path, loop count)
{AudibleAlert::CHIME_DISENGAGE, {"../assets/sounds/disengaged.wav", 0}},
{AudibleAlert::CHIME_ENGAGE, {"../assets/sounds/engaged.wav", 0}},
{AudibleAlert::CHIME_WARNING1, {"../assets/sounds/warning_1.wav", 0}},
{AudibleAlert::CHIME_WARNING2, {"../assets/sounds/warning_2.wav", 0}},
{AudibleAlert::CHIME_WARNING2_REPEAT, {"../assets/sounds/warning_2.wav", -1}},
{AudibleAlert::CHIME_WARNING_REPEAT, {"../assets/sounds/warning_repeat.wav", -1}},
{AudibleAlert::CHIME_ERROR, {"../assets/sounds/error.wav", 0}},
{AudibleAlert::CHIME_PROMPT, {"../assets/sounds/error.wav", 0}}
};
std::map<AudibleAlert, QSoundEffect> sounds;
};

View File

@ -7,25 +7,30 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) {
homeWindow = new HomeWindow(this);
main_layout->addWidget(homeWindow);
QObject::connect(homeWindow, &HomeWindow::openSettings, this, &MainWindow::openSettings);
QObject::connect(homeWindow, &HomeWindow::closeSettings, this, &MainWindow::closeSettings);
QObject::connect(&qs, &QUIState::uiUpdate, homeWindow, &HomeWindow::update);
QObject::connect(&qs, &QUIState::offroadTransition, homeWindow, &HomeWindow::offroadTransition);
QObject::connect(&device, &Device::displayPowerChanged, homeWindow, &HomeWindow::displayPowerChanged);
settingsWindow = new SettingsWindow(this);
main_layout->addWidget(settingsWindow);
QObject::connect(settingsWindow, &SettingsWindow::closeSettings, this, &MainWindow::closeSettings);
QObject::connect(&qs, &QUIState::offroadTransition, settingsWindow, &SettingsWindow::offroadTransition);
QObject::connect(settingsWindow, SIGNAL(reviewTrainingGuide()), this, SLOT(reviewTrainingGuide()));
onboardingWindow = new OnboardingWindow(this);
main_layout->addWidget(onboardingWindow);
QObject::connect(homeWindow, SIGNAL(openSettings()), this, SLOT(openSettings()));
QObject::connect(homeWindow, SIGNAL(closeSettings()), this, SLOT(closeSettings()));
QObject::connect(homeWindow, SIGNAL(offroadTransition(bool)), this, SLOT(offroadTransition(bool)));
QObject::connect(homeWindow, SIGNAL(offroadTransition(bool)), settingsWindow, SIGNAL(offroadTransition(bool)));
QObject::connect(settingsWindow, SIGNAL(closeSettings()), this, SLOT(closeSettings()));
QObject::connect(settingsWindow, SIGNAL(reviewTrainingGuide()), this, SLOT(reviewTrainingGuide()));
// start at onboarding
main_layout->setCurrentWidget(onboardingWindow);
QObject::connect(onboardingWindow, SIGNAL(onboardingDone()), this, SLOT(closeSettings()));
onboardingWindow->updateActiveScreen();
device.setAwake(true, true);
QObject::connect(&qs, &QUIState::uiUpdate, &device, &Device::update);
QObject::connect(&qs, &QUIState::offroadTransition, this, &MainWindow::offroadTransition);
QObject::connect(&device, &Device::displayPowerChanged, this, &MainWindow::closeSettings);
// no outline to prevent the focus rectangle
setLayout(main_layout);
setStyleSheet(R"(
@ -58,11 +63,11 @@ void MainWindow::reviewTrainingGuide() {
bool MainWindow::eventFilter(QObject *obj, QEvent *event){
// wake screen on tap
if (event->type() == QEvent::MouseButtonPress) {
homeWindow->glWindow->wake();
device.setAwake(true, true);
}
// filter out touches while in android activity
#ifdef QCOM
// filter out touches while in android activity
const QList<QEvent::Type> filter_events = {QEvent::MouseButtonPress, QEvent::MouseMove, QEvent::TouchBegin, QEvent::TouchUpdate, QEvent::TouchEnd};
if (HardwareEon::launched_activity && filter_events.contains(event->type())) {
HardwareEon::check_activity();

View File

@ -6,6 +6,7 @@
#include "offroad/settings.hpp"
#include "offroad/onboarding.hpp"
#include "home.hpp"
#include "../ui.hpp"
class MainWindow : public QWidget {
Q_OBJECT
@ -17,6 +18,9 @@ public:
explicit MainWindow(QWidget *parent = 0);
private:
Device device;
QUIState qs;
QStackedLayout *main_layout;
HomeWindow *homeWindow;
SettingsWindow *settingsWindow;

View File

@ -7,8 +7,16 @@
#include "common/util.h"
#include "common/swaglog.h"
#include "common/visionimg.h"
#include "common/watchdog.h"
#include "hardware/hw.h"
#include "ui.hpp"
#include "paint.hpp"
#include "qt_window.hpp"
#define BACKLIGHT_DT 0.25
#define BACKLIGHT_TS 2.00
#define BACKLIGHT_OFFROAD 50
// Projects a point in car to space to the corresponding point in full frame
// image space.
@ -45,34 +53,6 @@ static void ui_init_vision(UIState *s) {
assert(glGetError() == GL_NO_ERROR);
}
void ui_init(UIState *s) {
s->sm = new SubMaster({
"modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "liveLocationKalman",
"pandaState", "carParams", "driverState", "driverMonitoringState", "sensorEvents", "carState", "ubloxGnss",
#ifdef QCOM2
"roadCameraState",
#endif
});
s->scene.started = false;
s->status = STATUS_OFFROAD;
s->last_frame = nullptr;
s->wide_camera = false;
#ifdef QCOM2
s->wide_camera = Params().getBool("EnableWideCamera");
#endif
ui_nvg_init(s);
s->vipc_client_rear = new VisionIpcClient("camerad", s->wide_camera ? VISION_STREAM_RGB_WIDE : VISION_STREAM_RGB_BACK, true);
s->vipc_client_front = new VisionIpcClient("camerad", VISION_STREAM_RGB_FRONT, true);
s->vipc_client = s->vipc_client_rear;
}
static int get_path_length_idx(const cereal::ModelDataV2::XYZTData::Reader &line, const float path_height) {
const auto line_x = line.getX();
int max_idx = 0;
@ -347,11 +327,121 @@ static void update_status(UIState *s) {
started_prev = s->scene.started;
}
void ui_update(UIState *s) {
update_params(s);
update_sockets(s);
update_state(s);
update_status(s);
update_alert(s);
update_vision(s);
QUIState::QUIState(QObject *parent) : QObject(parent) {
ui_state.sound = std::make_unique<Sound>();
ui_state.sm = std::make_unique<SubMaster, const std::initializer_list<const char *>>({
"modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "liveLocationKalman",
"pandaState", "carParams", "driverState", "driverMonitoringState", "sensorEvents", "carState", "ubloxGnss",
#ifdef QCOM2
"roadCameraState",
#endif
});
ui_state.fb_w = vwp_w;
ui_state.fb_h = vwp_h;
ui_state.scene.started = false;
ui_state.status = STATUS_OFFROAD;
ui_state.last_frame = nullptr;
ui_state.wide_camera = false;
#ifdef QCOM2
ui_state.wide_camera = Params().getBool("EnableWideCamera");
#endif
ui_state.vipc_client_rear = new VisionIpcClient("camerad", ui_state.wide_camera ? VISION_STREAM_RGB_WIDE : VISION_STREAM_RGB_BACK, true);
ui_state.vipc_client_front = new VisionIpcClient("camerad", VISION_STREAM_RGB_FRONT, true);
ui_state.vipc_client = ui_state.vipc_client_rear;
// update timer
timer = new QTimer(this);
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(0);
}
void QUIState::update() {
update_params(&ui_state);
update_sockets(&ui_state);
update_state(&ui_state);
update_status(&ui_state);
update_alert(&ui_state);
update_vision(&ui_state);
if (ui_state.scene.started != started_prev) {
started_prev = ui_state.scene.started;
emit offroadTransition(!ui_state.scene.started);
// Change timeout to 0 when onroad, this will call update continously.
// This puts visionIPC in charge of update frequency, reducing video latency
timer->start(ui_state.scene.started ? 0 : 1000 / UI_FREQ);
}
// scale volume with speed
QUIState::ui_state.sound->volume = util::map_val(ui_state.scene.car_state.getVEgo(), 0.f, 20.f,
Hardware::MIN_VOLUME, Hardware::MAX_VOLUME);
watchdog_kick();
emit uiUpdate(ui_state);
}
Device::Device(QObject *parent) : brightness_filter(BACKLIGHT_OFFROAD, BACKLIGHT_TS, BACKLIGHT_DT), QObject(parent) {
brightness_b = Params(true).get<float>("BRIGHTNESS_B").value_or(10.0);
brightness_m = Params(true).get<float>("BRIGHTNESS_M").value_or(0.1);
}
void Device::update(const UIState &s) {
updateBrightness(s);
updateWakefulness(s);
// TODO: remove from UIState and use signals
QUIState::ui_state.awake = awake;
}
void Device::setAwake(bool on, bool reset) {
if (on != awake) {
awake = on;
Hardware::set_display_power(awake);
LOGD("setting display power %d", awake);
emit displayPowerChanged(awake);
}
if (reset) {
awake_timeout = 30 * UI_FREQ;
}
}
void Device::updateBrightness(const UIState &s) {
float clipped_brightness = std::min(100.0f, (s.scene.light_sensor * brightness_m) + brightness_b);
#ifdef QCOM2
if (!s.scene.started) {
clipped_brightness = BACKLIGHT_OFFROAD;
}
#endif
int brightness = brightness_filter.update(clipped_brightness);
if (!awake) {
brightness = 0;
}
if (brightness != last_brightness) {
std::thread{Hardware::set_brightness, brightness}.detach();
}
last_brightness = brightness;
}
void Device::updateWakefulness(const UIState &s) {
awake_timeout = std::max(awake_timeout - 1, 0);
bool should_wake = s.scene.started || s.scene.ignition;
if (!should_wake) {
// tap detection while display is off
bool accel_trigger = abs(s.scene.accel_sensor - accel_prev) > 0.2;
bool gyro_trigger = abs(s.scene.gyro_sensor - gyro_prev) > 0.15;
should_wake = accel_trigger && gyro_trigger;
gyro_prev = s.scene.gyro_sensor;
accel_prev = (accel_prev * (accel_samples - 1) + s.scene.accel_sensor) / accel_samples;
}
setAwake(awake_timeout, should_wake);
}

View File

@ -1,15 +1,4 @@
#pragma once
#include "messaging.hpp"
#ifdef __APPLE__
#include <OpenGL/gl3.h>
#define NANOVG_GL3_IMPLEMENTATION
#define nvgCreate nvgCreateGL3
#else
#include <GLES3/gl3.h>
#define NANOVG_GLES3_IMPLEMENTATION
#define nvgCreate nvgCreateGLES3
#endif
#include <atomic>
#include <map>
@ -19,16 +8,23 @@
#include "nanovg.h"
#include "camerad/cameras/camera_common.h"
#include "common/mat.h"
#include "common/visionimg.h"
#include "common/modeldata.h"
#include "common/params.h"
#include "common/glutil.h"
#include "common/util.h"
#include "common/transformations/orientation.hpp"
#include "qt/sound.hpp"
#include "messaging.hpp"
#include "visionipc.h"
#include "visionipc_client.h"
#include "qt/sound.hpp"
#include <QObject>
#include <QTimer>
#define COLOR_BLACK nvgRGBA(0, 0, 0, 255)
#define COLOR_BLACK_ALPHA(x) nvgRGBA(0, 0, 0, x)
#define COLOR_WHITE nvgRGBA(255, 255, 255, 255)
@ -37,8 +33,6 @@
#define COLOR_YELLOW nvgRGBA(218, 202, 37, 255)
#define COLOR_RED nvgRGBA(201, 34, 49, 255)
#define UI_BUF_COUNT 4
typedef struct Rect {
int x, y, w, h;
int centerX() const { return x + w / 2; }
@ -148,9 +142,9 @@ typedef struct UIState {
// images
std::map<std::string, int> images;
SubMaster *sm;
std::unique_ptr<SubMaster> sm;
Sound *sound;
std::unique_ptr<Sound> sound;
UIStatus status;
UIScene scene;
@ -161,7 +155,6 @@ typedef struct UIState {
GLuint frame_vao[2], frame_vbo[2], frame_ibo[2];
mat4 rear_frame_mat, front_frame_mat;
// device state
bool awake;
bool sidebar_collapsed;
@ -171,5 +164,59 @@ typedef struct UIState {
float zoom;
} UIState;
void ui_init(UIState *s);
void ui_update(UIState *s);
class QUIState : public QObject {
Q_OBJECT
public:
QUIState(QObject* parent = 0);
// TODO: get rid of this, only use signal
inline static UIState ui_state = {0};
signals:
void uiUpdate(const UIState &s);
void offroadTransition(bool offroad);
private slots:
void update();
private:
QTimer *timer;
bool started_prev = true;
};
// device management class
class Device : public QObject {
Q_OBJECT
public:
Device(QObject *parent = 0);
private:
// auto brightness
const float accel_samples = 5*UI_FREQ;
bool awake;
int awake_timeout = 0;
float accel_prev = 0;
float gyro_prev = 0;
float brightness_b = 0;
float brightness_m = 0;
float last_brightness = 0;
FirstOrderFilter brightness_filter;
QTimer *timer;
void updateBrightness(const UIState &s);
void updateWakefulness(const UIState &s);
signals:
void displayPowerChanged(bool on);
public slots:
void setAwake(bool on, bool reset);
void update(const UIState &s);
};