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.

195 lines
5.6 KiB

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/resource.h>
#include <algorithm>
#include "common/util.h"
#include "common/utilpp.h"
#include "common/params.h"
#include "common/touch.h"
#include "common/swaglog.h"
#include "ui.hpp"
#include "paint.hpp"
#include "android/sl_sound.hpp"
volatile sig_atomic_t do_exit = 0;
static void set_do_exit(int sig) {
do_exit = 1;
}
static void ui_set_brightness(UIState *s, int brightness) {
static int last_brightness = -1;
if (last_brightness != brightness && (s->awake || brightness == 0)) {
if (set_brightness(brightness)) {
last_brightness = brightness;
}
}
}
static void handle_display_state(UIState *s, bool user_input) {
static int awake_timeout = 0;
constexpr float accel_samples = 5*UI_FREQ;
static float accel_prev = 0., gyro_prev = 0.;
bool should_wake = s->started || s->ignition || user_input;
if (!should_wake) {
// tap detection while display is off
bool accel_trigger = abs(s->accel_sensor - accel_prev) > 0.2;
bool gyro_trigger = abs(s->gyro_sensor - gyro_prev) > 0.15;
should_wake = accel_trigger && gyro_trigger;
gyro_prev = s->gyro_sensor;
accel_prev = (accel_prev * (accel_samples - 1) + s->accel_sensor) / accel_samples;
}
// determine desired state
if (should_wake) {
awake_timeout = 30*UI_FREQ;
} else if (awake_timeout > 0){
--awake_timeout;
should_wake = true;
}
// handle state transition
if (s->awake != should_wake) {
s->awake = should_wake;
int display_mode = s->awake ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
LOGW("setting display mode %d", display_mode);
framebuffer_set_power(s->fb, display_mode);
if (s->awake) {
system("service call window 18 i32 1");
}
}
}
static void handle_vision_touch(UIState *s, int touch_x, int touch_y) {
if (s->started && (touch_x >= s->scene.viz_rect.x - bdr_s)
&& (s->active_app != cereal::UiLayoutState::App::SETTINGS)) {
if (!s->scene.frontview) {
s->scene.sidebar_collapsed = !s->scene.sidebar_collapsed;
} else {
Params().write_db_value("IsDriverViewEnabled", "0", 1);
}
}
}
static void handle_sidebar_touch(UIState *s, int touch_x, int touch_y) {
if (!s->scene.sidebar_collapsed && touch_x <= sbr_w) {
if (settings_btn.ptInRect(touch_x, touch_y)) {
s->active_app = cereal::UiLayoutState::App::SETTINGS;
} else if (home_btn.ptInRect(touch_x, touch_y)) {
if (s->started) {
s->active_app = cereal::UiLayoutState::App::NONE;
s->scene.sidebar_collapsed = true;
} else {
s->active_app = cereal::UiLayoutState::App::HOME;
}
}
}
}
static void update_offroad_layout_state(UIState *s, PubMaster *pm) {
static int timeout = 0;
static bool prev_collapsed = false;
static cereal::UiLayoutState::App prev_app = cereal::UiLayoutState::App::NONE;
if (timeout > 0) {
timeout--;
}
if (prev_collapsed != s->scene.sidebar_collapsed || prev_app != s->active_app || timeout == 0) {
MessageBuilder msg;
auto layout = msg.initEvent().initUiLayoutState();
layout.setActiveApp(s->active_app);
layout.setSidebarCollapsed(s->scene.sidebar_collapsed);
pm->send("offroadLayout", msg);
LOGD("setting active app to %d with sidebar %d", (int)s->active_app, s->scene.sidebar_collapsed);
prev_collapsed = s->scene.sidebar_collapsed;
prev_app = s->active_app;
timeout = 2 * UI_FREQ;
}
}
int main(int argc, char* argv[]) {
setpriority(PRIO_PROCESS, 0, -14);
signal(SIGINT, (sighandler_t)set_do_exit);
SLSound sound;
UIState uistate = {};
UIState *s = &uistate;
ui_init(s);
s->sound = &sound;
TouchState touch = {0};
touch_init(&touch);
handle_display_state(s, true);
PubMaster *pm = new PubMaster({"offroadLayout"});
// light sensor scaling and volume params
const bool LEON = util::read_file("/proc/cmdline").find("letv") != std::string::npos;
float brightness_b = 0, brightness_m = 0;
int result = read_param(&brightness_b, "BRIGHTNESS_B", true);
result += read_param(&brightness_m, "BRIGHTNESS_M", true);
if (result != 0) {
brightness_b = LEON ? 10.0 : 5.0;
brightness_m = LEON ? 2.6 : 1.3;
write_param_float(brightness_b, "BRIGHTNESS_B", true);
write_param_float(brightness_m, "BRIGHTNESS_M", true);
}
float smooth_brightness = brightness_b;
const int MIN_VOLUME = LEON ? 12 : 9;
const int MAX_VOLUME = LEON ? 15 : 12;
s->sound->setVolume(MIN_VOLUME);
while (!do_exit) {
if (!s->started) {
usleep(50 * 1000);
}
double u1 = millis_since_boot();
ui_update(s);
// poll for touch events
int touch_x = -1, touch_y = -1;
int touched = touch_poll(&touch, &touch_x, &touch_y, 0);
if (touched == 1) {
handle_sidebar_touch(s, touch_x, touch_y);
handle_vision_touch(s, touch_x, touch_y);
}
// Don't waste resources on drawing in case screen is off
handle_display_state(s, touched == 1);
if (!s->awake) {
continue;
}
// up one notch every 5 m/s
s->sound->setVolume(fmin(MAX_VOLUME, MIN_VOLUME + s->scene.controls_state.getVEgo() / 5));
// set brightness
float clipped_brightness = fmin(512, (s->light_sensor*brightness_m) + brightness_b);
smooth_brightness = fmin(255, clipped_brightness * 0.01 + smooth_brightness * 0.99);
ui_set_brightness(s, (int)smooth_brightness);
update_offroad_layout_state(s, pm);
ui_draw(s);
double u2 = millis_since_boot();
if (!s->scene.frontview && (u2-u1 > 66)) {
// warn on sub 15fps
LOGW("slow frame(%llu) time: %.2f", (s->sm)->frame, u2-u1);
}
framebuffer_swap(s->fb);
}
handle_display_state(s, true);
delete s->sm;
delete pm;
return 0;
}