#include #include #include #include #include "common/util.h" #include "common/utilpp.h" #include "common/params.h" #include "common/touch.h" #include "common/timing.h" #include "common/swaglog.h" #include "ui.hpp" #include "paint.hpp" #include "android/sl_sound.hpp" // Includes for light sensor #include #include #include volatile sig_atomic_t do_exit = 0; static void set_do_exit(int sig) { do_exit = 1; } static void* light_sensor_thread(void *args) { set_thread_name("light_sensor"); int err; UIState *s = (UIState*)args; s->light_sensor = 0.0; struct sensors_poll_device_t* device; struct sensors_module_t* module; hw_get_module(SENSORS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); sensors_open(&module->common, &device); // need to do this struct sensor_t const* list; module->get_sensors_list(module, &list); int SENSOR_LIGHT = 7; err = device->activate(device, SENSOR_LIGHT, 0); if (err != 0) goto fail; err = device->activate(device, SENSOR_LIGHT, 1); if (err != 0) goto fail; device->setDelay(device, SENSOR_LIGHT, ms2ns(100)); while (!do_exit) { static const size_t numEvents = 1; sensors_event_t buffer[numEvents]; int n = device->poll(device, buffer, numEvents); if (n < 0) { LOG_100("light_sensor_poll failed: %d", n); } if (n > 0) { s->light_sensor = buffer[0].light; } } sensors_close(device); return NULL; fail: LOGE("LIGHT SENSOR IS MISSING"); s->light_sensor = 255; return NULL; } 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; } } static void set_awake(UIState *s, bool awake) { if (awake) { // 30 second timeout s->awake_timeout = 30*UI_FREQ; } if (s->awake != awake) { s->awake = awake; // TODO: replace command_awake and command_sleep with direct calls to android if (awake) { LOGW("awake normal"); framebuffer_set_power(s->fb, HWC_POWER_MODE_NORMAL); enable_event_processing(true); } else { LOGW("awake off"); ui_set_brightness(s, 0); framebuffer_set_power(s->fb, HWC_POWER_MODE_OFF); enable_event_processing(false); } } } static void handle_vision_touch(UIState *s, int touch_x, int touch_y) { if (s->started && (touch_x >= s->scene.ui_viz_rx - bdr_s) && (s->active_app != cereal::UiLayoutState::App::SETTINGS)) { if (!s->scene.frontview) { s->scene.uilayout_sidebarcollapsed = !s->scene.uilayout_sidebarcollapsed; } else { 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 (touch_x >= settings_btn_x && touch_x < (settings_btn_x + settings_btn_w) && touch_y >= settings_btn_y && touch_y < (settings_btn_y + settings_btn_h)) { s->active_app = cereal::UiLayoutState::App::SETTINGS; } else if (touch_x >= home_btn_x && touch_x < (home_btn_x + home_btn_w) && touch_y >= home_btn_y && touch_y < (home_btn_y + home_btn_h)) { 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) { capnp::MallocMessageBuilder msg; auto event = msg.initRoot(); event.setLogMonoTime(nanos_since_boot()); auto layout = event.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[]) { int err; 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; set_awake(s, true); enable_event_processing(true); PubMaster *pm = new PubMaster({"offroadLayout"}); pthread_t light_sensor_thread_handle; err = pthread_create(&light_sensor_thread_handle, NULL, light_sensor_thread, s); assert(err == 0); 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) { set_awake(s, true); handle_sidebar_touch(s, touch_x, touch_y); handle_vision_touch(s, touch_x, touch_y); } // manage wakefulness if (s->started || s->ignition) { set_awake(s, true); } if (s->awake_timeout > 0) { s->awake_timeout--; } else { set_awake(s, false); } // Don't waste resources on drawing in case screen is off 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); } set_awake(s, true); err = pthread_join(light_sensor_thread_handle, NULL); assert(err == 0); delete s->sm; delete pm; return 0; }