#include #include #include #include #include #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; } } } int event_processing_enabled = -1; static void enable_event_processing(bool yes) { if (event_processing_enabled != 1 && yes) { system("service call window 18 i32 1"); // enable event processing event_processing_enabled = 1; } else if (event_processing_enabled != 0 && !yes) { system("service call window 18 i32 0"); // disable event processing event_processing_enabled = 0; } } // TODO: implement double tap to wake and actually turn display off static void handle_display_state(UIState *s, bool user_input) { static int display_mode = HWC_POWER_MODE_OFF; static int display_timeout = 0; // determine desired state int desired_mode = display_mode; if (user_input || s->ignition || s->started) { desired_mode = HWC_POWER_MODE_NORMAL; display_timeout = 30*UI_FREQ; } else { display_timeout = std::max(display_timeout-1, 0); if (display_timeout == 0) { desired_mode = HWC_POWER_MODE_DOZE; } } // handle state transition if (display_mode != desired_mode) { LOGW("setting display mode %d", desired_mode); display_mode = desired_mode; s->awake = display_mode == HWC_POWER_MODE_NORMAL; framebuffer_set_power(s->fb, display_mode); enable_event_processing(s->awake); if (!s->awake) { ui_set_brightness(s, 0); } } } 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.uilayout_sidebarcollapsed = !s->scene.uilayout_sidebarcollapsed; } else { Params().write_db_value("IsDriverViewEnabled", "0", 1); } } } static void handle_sidebar_touch(UIState *s, int touch_x, int touch_y) { if (!s->scene.uilayout_sidebarcollapsed && 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.uilayout_sidebarcollapsed = 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.uilayout_sidebarcollapsed || prev_app != s->active_app || timeout == 0) { MessageBuilder msg; auto layout = msg.initEvent().initUiLayoutState(); layout.setActiveApp(s->active_app); layout.setSidebarCollapsed(s->scene.uilayout_sidebarcollapsed); pm->send("offroadLayout", msg); LOGD("setting active app to %d with sidebar %d", (int)s->active_app, s->scene.uilayout_sidebarcollapsed); prev_collapsed = s->scene.uilayout_sidebarcollapsed; 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; handle_display_state(s, true); enable_event_processing(true); PubMaster *pm = new PubMaster({"offroadLayout"}); TouchState touch = {0}; touch_init(&touch); // 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 || !s->vision_connected) { // Delay a while to avoid 9% cpu usage while car is not started and user is keeping touching on the screen. usleep(30 * 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; }