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
Adeeb Shihadeh 2021-03-10 22:51:50 -08:00 committed by GitHub
parent baf07191d2
commit d45550c424
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 165 additions and 102 deletions

View File

@ -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

View File

@ -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();
}
};
};

View File

@ -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;

View File

@ -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() {}

View File

@ -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();

View File

@ -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());
}
}

View File

@ -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;

View File

@ -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