UI HW Abstraction layer (#20301)
* start cpp hw abstraction layer * cleanup * only set brightness on change * confirmation dialogs * add to release files * fix tici brightness * using percentage now Co-authored-by: Comma Device <device@comma.ai>pull/20308/head
parent
baf07191d2
commit
d45550c424
|
@ -264,6 +264,7 @@ selfdrive/controls/lib/longitudinal_mpc_model/longitudinal_mpc.c
|
|||
|
||||
selfdrive/hardware/__init__.py
|
||||
selfdrive/hardware/base.py
|
||||
selfdrive/hardware/hw.h
|
||||
selfdrive/hardware/eon/__init__.py
|
||||
selfdrive/hardware/eon/apk.py
|
||||
selfdrive/hardware/eon/hardware.py
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
|
||||
#include <common/util.h>
|
||||
|
||||
#ifdef QCOM
|
||||
#define Hardware HardwareEon
|
||||
#elif QCOM2
|
||||
#define Hardware HardwareTici
|
||||
#else
|
||||
#define Hardware HardwareNone
|
||||
#endif
|
||||
|
||||
|
||||
// no-op base hw class
|
||||
class HardwareNone {
|
||||
public:
|
||||
static std::string get_os_version() { return "openpilot for PC"; };
|
||||
|
||||
static void reboot() {};
|
||||
static void poweroff() {};
|
||||
static void set_brightness(int percent) {};
|
||||
};
|
||||
|
||||
class HardwareEon : public HardwareNone {
|
||||
public:
|
||||
static std::string get_os_version() {
|
||||
return "NEOS " + util::read_file("/VERSION");
|
||||
};
|
||||
|
||||
static void reboot() { std::system("reboot"); };
|
||||
static void poweroff() { std::system("LD_LIBRARY_PATH= svc power shutdown"); };
|
||||
static void set_brightness(int percent) {
|
||||
std::ofstream brightness_control("/sys/class/leds/lcd-backlight/brightness");
|
||||
if (brightness_control.is_open()) {
|
||||
brightness_control << (int)(percent * (255/100.)) << "\n";
|
||||
brightness_control.close();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class HardwareTici : public HardwareNone {
|
||||
public:
|
||||
static std::string get_os_version() {
|
||||
return "AGNOS " + util::read_file("/VERSION");
|
||||
};
|
||||
|
||||
static void reboot() { std::system("sudo reboot"); };
|
||||
static void poweroff() { std::system("sudo poweroff"); };
|
||||
static void set_brightness(int percent) {
|
||||
std::ofstream brightness_control("/sys/class/backlight/panel0-backlight/brightness");
|
||||
if (brightness_control.is_open()) {
|
||||
brightness_control << (percent * (1023/100.)) << "\n";
|
||||
brightness_control.close();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -5,10 +5,11 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common/framebuffer.h"
|
||||
#include "common/util.h"
|
||||
#include "common/params.h"
|
||||
#include "common/touch.h"
|
||||
#include "common/swaglog.h"
|
||||
#include "common/touch.h"
|
||||
#include "common/watchdog.h"
|
||||
|
||||
#include "ui.hpp"
|
||||
|
@ -25,7 +26,7 @@ static void ui_set_brightness(UIState *s, int brightness) {
|
|||
}
|
||||
}
|
||||
|
||||
static void handle_display_state(UIState *s, bool user_input) {
|
||||
static void handle_display_state(UIState *s, FrameBuffer *fb, bool user_input) {
|
||||
static int awake_timeout = 0;
|
||||
|
||||
constexpr float accel_samples = 5*UI_FREQ;
|
||||
|
@ -54,7 +55,7 @@ static void handle_display_state(UIState *s, bool user_input) {
|
|||
s->awake = should_wake;
|
||||
int display_mode = s->awake ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
|
||||
LOGW("setting display mode %d", display_mode);
|
||||
s->fb->set_power(display_mode);
|
||||
fb->set_power(display_mode);
|
||||
|
||||
if (s->awake) {
|
||||
system("service call window 18 i32 1");
|
||||
|
@ -110,16 +111,18 @@ static void update_offroad_layout_state(UIState *s, PubMaster *pm) {
|
|||
|
||||
int main(int argc, char* argv[]) {
|
||||
setpriority(PRIO_PROCESS, 0, -14);
|
||||
SLSound sound;
|
||||
|
||||
SLSound sound;
|
||||
UIState uistate = {};
|
||||
UIState *s = &uistate;
|
||||
FrameBuffer fb = FrameBuffer("ui", 0, true, &s->fb_w, &s->fb_h);
|
||||
|
||||
ui_init(s);
|
||||
s->sound = &sound;
|
||||
|
||||
TouchState touch = {0};
|
||||
touch_init(&touch);
|
||||
handle_display_state(s, true);
|
||||
handle_display_state(s, &fb, true);
|
||||
|
||||
PubMaster *pm = new PubMaster({"offroadLayout"});
|
||||
|
||||
|
@ -157,7 +160,7 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
|
||||
// Don't waste resources on drawing in case screen is off
|
||||
handle_display_state(s, touched == 1);
|
||||
handle_display_state(s, &fb, touched == 1);
|
||||
if (!s->awake) {
|
||||
continue;
|
||||
}
|
||||
|
@ -178,10 +181,10 @@ int main(int argc, char* argv[]) {
|
|||
// warn on sub 15fps
|
||||
LOGW("slow frame(%llu) time: %.2f", (s->sm)->frame, u2-u1);
|
||||
}
|
||||
s->fb->swap();
|
||||
fb.swap();
|
||||
}
|
||||
|
||||
handle_display_state(s, true);
|
||||
handle_display_state(s, &fb, true);
|
||||
delete s->sm;
|
||||
delete pm;
|
||||
return 0;
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include <thread>
|
||||
#include <exception>
|
||||
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLayout>
|
||||
|
@ -17,6 +16,7 @@
|
|||
#include "common/timing.h"
|
||||
#include "common/swaglog.h"
|
||||
#include "common/watchdog.h"
|
||||
#include "selfdrive/hardware/hw.h"
|
||||
|
||||
#include "home.hpp"
|
||||
#include "paint.hpp"
|
||||
|
@ -26,7 +26,61 @@
|
|||
|
||||
#define BACKLIGHT_DT 0.25
|
||||
#define BACKLIGHT_TS 2.00
|
||||
#define BACKLIGHT_OFFROAD 512
|
||||
#define BACKLIGHT_OFFROAD 50
|
||||
|
||||
// HomeWindow: the container for the offroad (OffroadHome) and onroad (GLWindow) UIs
|
||||
|
||||
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(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);
|
||||
setStyleSheet(R"(
|
||||
* {
|
||||
color: white;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
void HomeWindow::setVisibility(bool offroad) {
|
||||
home->setVisible(offroad);
|
||||
}
|
||||
|
||||
void HomeWindow::mousePressEvent(QMouseEvent* e) {
|
||||
UIState* ui_state = &glWindow->ui_state;
|
||||
if (GLWindow::ui_state.scene.started && 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();
|
||||
}
|
||||
|
||||
// Vision click
|
||||
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();
|
||||
|
@ -109,7 +163,6 @@ void OffroadHome::refresh() {
|
|||
}
|
||||
|
||||
if (alerts_widget->updateAvailable) {
|
||||
// There is a new release
|
||||
alert_notification->setText("UPDATE");
|
||||
} else {
|
||||
int alerts = alerts_widget->alerts.size();
|
||||
|
@ -135,55 +188,8 @@ void OffroadHome::refresh() {
|
|||
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(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);
|
||||
setStyleSheet(R"(
|
||||
* {
|
||||
color: white;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
void HomeWindow::setVisibility(bool offroad) {
|
||||
home->setVisible(offroad);
|
||||
}
|
||||
|
||||
void HomeWindow::mousePressEvent(QMouseEvent* e) {
|
||||
UIState* ui_state = &glWindow->ui_state;
|
||||
if (GLWindow::ui_state.scene.started && 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();
|
||||
}
|
||||
|
||||
// Vision click
|
||||
if (ui_state->scene.started && (e->x() >= ui_state->viz_rect.x - bdr_s)) {
|
||||
ui_state->sidebar_collapsed = !ui_state->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
|
||||
static int awake_timeout = 0;
|
||||
awake_timeout = std::max(awake_timeout - 1, 0);
|
||||
|
||||
if (user_input || s->scene.ignition || s->scene.started) {
|
||||
|
@ -194,17 +200,8 @@ static void handle_display_state(UIState* s, bool user_input) {
|
|||
}
|
||||
}
|
||||
|
||||
static void set_backlight(int brightness) {
|
||||
try {
|
||||
std::ofstream brightness_control("/sys/class/backlight/panel0-backlight/brightness");
|
||||
if (brightness_control.is_open()) {
|
||||
brightness_control << brightness << "\n";
|
||||
brightness_control.close();
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
qDebug() << "Error setting brightness";
|
||||
}
|
||||
}
|
||||
|
||||
// GLWindow: the onroad UI
|
||||
|
||||
GLWindow::GLWindow(QWidget* parent) : QOpenGLWidget(parent) {
|
||||
timer = new QTimer(this);
|
||||
|
@ -217,7 +214,7 @@ GLWindow::GLWindow(QWidget* parent) : QOpenGLWidget(parent) {
|
|||
result += read_param(&brightness_m, "BRIGHTNESS_M", true);
|
||||
if (result != 0) {
|
||||
brightness_b = 10.0;
|
||||
brightness_m = 1.0;
|
||||
brightness_m = 0.1;
|
||||
}
|
||||
smooth_brightness = BACKLIGHT_OFFROAD;
|
||||
}
|
||||
|
@ -235,6 +232,8 @@ void GLWindow::initializeGL() {
|
|||
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();
|
||||
|
@ -248,18 +247,23 @@ void GLWindow::backlightUpdate() {
|
|||
// Update brightness
|
||||
float k = (BACKLIGHT_DT / BACKLIGHT_TS) / (1.0f + BACKLIGHT_DT / BACKLIGHT_TS);
|
||||
|
||||
float clipped_brightness = ui_state.scene.started ?
|
||||
std::min(1023.0f, (ui_state.scene.light_sensor * brightness_m) + brightness_b) : BACKLIGHT_OFFROAD;
|
||||
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();
|
||||
}
|
||||
std::thread{set_backlight, brightness}.detach();
|
||||
|
||||
if (brightness != last_brightness) {
|
||||
std::thread{Hardware::set_brightness, brightness}.detach();
|
||||
}
|
||||
last_brightness = brightness;
|
||||
}
|
||||
|
||||
void GLWindow::timerUpdate() {
|
||||
|
@ -296,9 +300,7 @@ void GLWindow::paintGL() {
|
|||
double dt = cur_draw_t - prev_draw_t;
|
||||
if (dt > 66 && onroad){
|
||||
// warn on sub 15fps
|
||||
#ifdef QCOM2
|
||||
LOGW("slow frame(%llu) time: %.2f", ui_state.sm->frame, dt);
|
||||
#endif
|
||||
}
|
||||
prev_draw_t = cur_draw_t;
|
||||
}
|
||||
|
@ -307,9 +309,3 @@ void GLWindow::paintGL() {
|
|||
void GLWindow::wake() {
|
||||
handle_display_state(&ui_state, true);
|
||||
}
|
||||
|
||||
FrameBuffer::FrameBuffer(const char *name, uint32_t layer, int alpha, int *out_w, int *out_h) {
|
||||
*out_w = vwp_w;
|
||||
*out_h = vwp_h;
|
||||
}
|
||||
FrameBuffer::~FrameBuffer() {}
|
||||
|
|
|
@ -44,10 +44,11 @@ private:
|
|||
bool onroad = true;
|
||||
double prev_draw_t = 0;
|
||||
|
||||
// TODO: this shouldn't be here
|
||||
// TODO: make a nice abstraction to handle embedded device stuff
|
||||
float brightness_b = 0;
|
||||
float brightness_m = 0;
|
||||
float smooth_brightness = 0;
|
||||
float last_brightness = 0;
|
||||
|
||||
public slots:
|
||||
void timerUpdate();
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "common/params.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "selfdrive/hardware/hw.h"
|
||||
|
||||
QFrame* horizontal_line(QWidget* parent = 0){
|
||||
QFrame* line = new QFrame(parent);
|
||||
line->setFrameShape(QFrame::StyledPanel);
|
||||
|
@ -170,15 +172,25 @@ QWidget * device_panel() {
|
|||
}
|
||||
});
|
||||
|
||||
// power buttons
|
||||
|
||||
QPushButton *poweroff_btn = new QPushButton("Power Off");
|
||||
device_layout->addWidget(poweroff_btn, Qt::AlignBottom);
|
||||
QObject::connect(poweroff_btn, &QPushButton::released, [=]() {
|
||||
if (ConfirmationDialog::confirm("Are you sure you want to power off?")) {
|
||||
Hardware::poweroff();
|
||||
}
|
||||
});
|
||||
|
||||
device_layout->addWidget(horizontal_line(), Qt::AlignBottom);
|
||||
|
||||
QPushButton *reboot_btn = new QPushButton("Reboot");
|
||||
device_layout->addWidget(reboot_btn, Qt::AlignBottom);
|
||||
device_layout->addWidget(horizontal_line(), Qt::AlignBottom);
|
||||
#ifdef __aarch64__
|
||||
QObject::connect(poweroff_btn, &QPushButton::released, [=]() { std::system("sudo poweroff"); });
|
||||
QObject::connect(reboot_btn, &QPushButton::released, [=]() { std::system("sudo reboot"); });
|
||||
#endif
|
||||
QObject::connect(reboot_btn, &QPushButton::released, [=]() {
|
||||
if (ConfirmationDialog::confirm("Are you sure you want to reboot?")) {
|
||||
Hardware::reboot();
|
||||
}
|
||||
});
|
||||
|
||||
QPushButton *uninstall_btn = new QPushButton("Uninstall openpilot");
|
||||
device_layout->addWidget(uninstall_btn);
|
||||
|
@ -205,8 +217,6 @@ QWidget * developer_panel() {
|
|||
QVBoxLayout *main_layout = new QVBoxLayout;
|
||||
main_layout->setMargin(100);
|
||||
|
||||
// TODO: enable SSH toggle and github keys
|
||||
|
||||
Params params = Params();
|
||||
std::string brand = params.read_db_bool("Passive") ? "dashcam" : "openpilot";
|
||||
std::vector<std::pair<std::string, std::string>> labels = {
|
||||
|
@ -214,18 +224,14 @@ QWidget * developer_panel() {
|
|||
{"Git Branch", params.get("GitBranch", false)},
|
||||
{"Git Commit", params.get("GitCommit", false).substr(0, 10)},
|
||||
{"Panda Firmware", params.get("PandaFirmwareHex", false)},
|
||||
{"OS Version", Hardware::get_os_version()},
|
||||
};
|
||||
|
||||
std::string os_version = util::read_file("/VERSION");
|
||||
if (os_version.size()) {
|
||||
labels.push_back({"OS Version", "AGNOS " + os_version});
|
||||
}
|
||||
|
||||
for (int i = 0; i<labels.size(); i++) {
|
||||
for (int i = 0; i < labels.size(); i++) {
|
||||
auto l = labels[i];
|
||||
main_layout->addWidget(labelWidget(QString::fromStdString(l.first), QString::fromStdString(l.second)));
|
||||
|
||||
if(i+1<labels.size()) {
|
||||
if(i+1 < labels.size()) {
|
||||
main_layout->addWidget(horizontal_line());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,8 +65,6 @@ void ui_init(UIState *s) {
|
|||
s->scene.started = false;
|
||||
s->status = STATUS_OFFROAD;
|
||||
|
||||
s->fb = std::make_unique<FrameBuffer>("ui", 0, true, &s->fb_w, &s->fb_h);
|
||||
|
||||
ui_nvg_init(s);
|
||||
|
||||
s->last_frame = nullptr;
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include "common/mat.h"
|
||||
#include "common/visionimg.h"
|
||||
#include "common/framebuffer.h"
|
||||
#include "common/modeldata.h"
|
||||
#include "common/params.h"
|
||||
#include "common/glutil.h"
|
||||
|
@ -144,7 +143,6 @@ typedef struct UIState {
|
|||
VisionBuf * last_frame;
|
||||
|
||||
// framebuffer
|
||||
std::unique_ptr<FrameBuffer> fb;
|
||||
int fb_w, fb_h;
|
||||
|
||||
// NVG
|
||||
|
|
Loading…
Reference in New Issue