Refactor frame (#1192)

* start drawing new sidebar, add assets

* add thermal to ui, draw network_type and battery

* draw sidebar metrics, add freeSpace and paTemp

* draw static panda metric and network strength, start ubloxGnss messaging

* use array for network_img

* start sidebar touch events

* prevent multiple touch events with touch_timeout

* filter old touches, isolate sidebar events

* add hwType check with timeout for panda metric

* cleanup touch poll, handle vision touch, remove frame and black apks

* cleanup per willem comments

* update offroad, only read active_app from cereal

* tweak sidebar behavior, show active app status

* update offroad apk

* read networkstrength from thermal in sidebar
old-commit-hash: 5ba6beed17
commatwo_master
Andrew Valish 5 years ago committed by GitHub
parent bde7a63cd7
commit 20816d909d
  1. 3
      apk/ai.comma.plus.black.apk
  2. 3
      apk/ai.comma.plus.frame.apk
  3. 4
      apk/ai.comma.plus.offroad.apk
  4. 7
      common/apk.py
  5. 3
      selfdrive/assets/images/battery.png
  6. 3
      selfdrive/assets/images/battery_charging.png
  7. 3
      selfdrive/assets/images/button_home.png
  8. 3
      selfdrive/assets/images/button_settings.png
  9. 3
      selfdrive/assets/images/network_0.png
  10. 3
      selfdrive/assets/images/network_1.png
  11. 3
      selfdrive/assets/images/network_2.png
  12. 3
      selfdrive/assets/images/network_3.png
  13. 3
      selfdrive/assets/images/network_4.png
  14. 3
      selfdrive/assets/images/network_5.png
  15. 6
      selfdrive/manager.py
  16. 4
      selfdrive/test/test_openpilot.py
  17. 2
      selfdrive/ui/SConscript
  18. 20
      selfdrive/ui/paint.cc
  19. 234
      selfdrive/ui/sidebar.cc
  20. 178
      selfdrive/ui/ui.cc
  21. 39
      selfdrive/ui/ui.hpp

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:309b46b7c38f10da52b18b0340eb3c57b633558a9a27c3ca4116474969ebb456
size 84675

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d563bc9d43408f78d859538b50999cd7703487bdbe1fba1b11a3810205cd26c4
size 2856327

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:bf9cdba9b1f10d7b76573d1f78d208bc58a7273ae5d5e6f171be6c00c67863a6 oid sha256:deb70c5a5b284e73d4960b60ac7a6dcc1263597762554749adf675c23efc383e
size 13678787 size 13688133

@ -6,7 +6,7 @@ import shutil
from common.basedir import BASEDIR from common.basedir import BASEDIR
from selfdrive.swaglog import cloudlog from selfdrive.swaglog import cloudlog
android_packages = ("ai.comma.plus.offroad", "ai.comma.plus.frame") android_packages = ("ai.comma.plus.offroad",)
def get_installed_apks(): def get_installed_apks():
dat = subprocess.check_output(["pm", "list", "packages", "-f"], encoding='utf8').strip().split("\n") dat = subprocess.check_output(["pm", "list", "packages", "-f"], encoding='utf8').strip().split("\n")
@ -26,9 +26,9 @@ def install_apk(path):
os.remove(install_path) os.remove(install_path)
return ret == 0 return ret == 0
def start_frame(): def start_offroad():
set_package_permissions() set_package_permissions()
system("am start -n ai.comma.plus.frame/.MainActivity") system("am start -n ai.comma.plus.offroad/.MainActivity")
def set_package_permissions(): def set_package_permissions():
pm_grant("ai.comma.plus.offroad", "android.permission.ACCESS_FINE_LOCATION") pm_grant("ai.comma.plus.offroad", "android.permission.ACCESS_FINE_LOCATION")
@ -95,4 +95,3 @@ def pm_apply_packages(cmd):
if __name__ == "__main__": if __name__ == "__main__":
update_apks() update_apks()

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2996f1558686dec3ea09b73b9a4bc5819c5f10a17611ccd267a61eab03e3d55b
size 1704

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1825c86dab73661002f8895c4bddf43c45aa50e0c5899ddc1b8cfde52d6942ec
size 2131

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3fca2a1f675cad4f454f3ba56d6e7f090a352321b61f241fc2ffcbede7a7593a
size 1501

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9ec603a5e8f08eb46512c8f0fbb684ff93533964b13a8a8ce45aec95b85e3800
size 957

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3bafba8ccc7166a430c4147159da31c989b4c1343585df90a6d60b6ca53fd3da
size 416

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a202db2a98d2564926d45fa1b890a62ed902a4246359ff4a96df1336d0d7569e
size 462

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1b2f5efdcb4c4d0fa3620e12c4aec2a4bf250ce72d2cf93ee34e754c7e055c71
size 593

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:74b690ab1f789f7a3ad0182e79f47c40f3145e586efb82582842dc3e4d375274
size 524

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3a0109067d5ba99087d0678b1b2d5e9b90ae63b2750b06c8c497a073d111ca15
size 541

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:827996c0c1f975dde1818ad66155c7564aa37a6019b841d3070b038c3e6d2860
size 503

@ -129,7 +129,7 @@ from selfdrive.version import version, dirty
from selfdrive.loggerd.config import ROOT from selfdrive.loggerd.config import ROOT
from selfdrive.launcher import launcher from selfdrive.launcher import launcher
from common import android from common import android
from common.apk import update_apks, pm_apply_packages, start_frame from common.apk import update_apks, pm_apply_packages, start_offroad
from common.manager_helpers import print_cpu_usage from common.manager_helpers import print_cpu_usage
ThermalStatus = cereal.log.ThermalData.ThermalStatus ThermalStatus = cereal.log.ThermalData.ThermalStatus
@ -406,10 +406,10 @@ def manager_thread():
for p in persistent_processes: for p in persistent_processes:
start_managed_process(p) start_managed_process(p)
# start frame # start offroad
if ANDROID: if ANDROID:
pm_apply_packages('enable') pm_apply_packages('enable')
start_frame() start_offroad()
if os.getenv("NOBOARD") is None: if os.getenv("NOBOARD") is None:
start_managed_process("pandad") start_managed_process("pandad")

@ -2,7 +2,7 @@
import os import os
os.environ['FAKEUPLOAD'] = "1" os.environ['FAKEUPLOAD'] = "1"
from common.apk import update_apks, start_frame, pm_apply_packages, android_packages from common.apk import update_apks, start_offroad, pm_apply_packages, android_packages
from common.params import Params from common.params import Params
from common.testing import phone_only from common.testing import phone_only
from selfdrive.manager import manager_init, manager_prepare from selfdrive.manager import manager_init, manager_prepare
@ -57,7 +57,7 @@ def with_apks():
update_apks() update_apks()
pm_apply_packages('enable') pm_apply_packages('enable')
start_frame() start_offroad()
func() func()

@ -1,6 +1,6 @@
Import('env', 'arch', 'common', 'messaging', 'gpucommon', 'visionipc', 'cereal') Import('env', 'arch', 'common', 'messaging', 'gpucommon', 'visionipc', 'cereal')
src = ['ui.cc', 'paint.cc', '#phonelibs/nanovg/nanovg.c'] src = ['ui.cc', 'paint.cc', 'sidebar.cc', '#phonelibs/nanovg/nanovg.c']
libs = [common, 'zmq', 'czmq', 'capnp', 'capnp_c', 'm', cereal, messaging, gpucommon, visionipc] libs = [common, 'zmq', 'czmq', 'capnp', 'capnp_c', 'm', cereal, messaging, gpucommon, visionipc]
if arch == "aarch64": if arch == "aarch64":

@ -877,6 +877,7 @@ static void ui_draw_blank(UIState *s) {
} }
void ui_draw(UIState *s) { void ui_draw(UIState *s) {
ui_draw_sidebar(s);
if (s->vision_connected && s->active_app == cereal_UiLayoutState_App_home && s->status != STATUS_STOPPED) { if (s->vision_connected && s->active_app == cereal_UiLayoutState_App_home && s->status != STATUS_STOPPED) {
ui_draw_vision(s); ui_draw_vision(s);
} else { } else {
@ -985,6 +986,25 @@ void ui_nvg_init(UIState *s) {
assert(s->img_map >= 0); assert(s->img_map >= 0);
s->img_map = nvgCreateImage(s->vg, "../assets/img_map.png", 1); s->img_map = nvgCreateImage(s->vg, "../assets/img_map.png", 1);
assert(s->img_button_settings >= 0);
s->img_button_settings = nvgCreateImage(s->vg, "../assets/images/button_settings.png", 1);
assert(s->img_button_home >= 0);
s->img_button_home = nvgCreateImage(s->vg, "../assets/images/button_home.png", 1);
assert(s->img_battery >= 0);
s->img_battery = nvgCreateImage(s->vg, "../assets/images/battery.png", 1);
assert(s->img_battery_charging >= 0);
s->img_battery_charging = nvgCreateImage(s->vg, "../assets/images/battery_charging.png", 1);
for(int i=0;i<=5;++i) {
assert(s->img_network[i] >= 0);
char network_asset[32];
snprintf(network_asset, sizeof(network_asset), "../assets/images/network_%d.png", i);
s->img_network[i] = nvgCreateImage(s->vg, network_asset, 1);
}
// init gl // init gl
s->frame_program = load_program(frame_vertex_shader, frame_fragment_shader); s->frame_program = load_program(frame_vertex_shader, frame_fragment_shader);
assert(s->frame_program); assert(s->frame_program);

@ -0,0 +1,234 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "ui.hpp"
static void ui_draw_sidebar_background(UIState *s, bool hasSidebar) {
int sbr_x = hasSidebar ? 0 : -(sbr_w) + bdr_s * 2;
nvgBeginPath(s->vg);
nvgRect(s->vg, sbr_x, 0, sbr_w, vwp_h);
nvgFillColor(s->vg, COLOR_BLACK_ALPHA);
nvgFill(s->vg);
}
static void ui_draw_sidebar_settings_button(UIState *s, bool hasSidebar) {
bool settingsActive = s->active_app == cereal_UiLayoutState_App_settings;
const int settings_btn_xr = hasSidebar ? settings_btn_x : -(sbr_w);
nvgBeginPath(s->vg);
NVGpaint imgPaint = nvgImagePattern(s->vg, settings_btn_xr, settings_btn_y,
settings_btn_w, settings_btn_h, 0, s->img_button_settings, settingsActive ? 1.0f : 0.65f);
nvgRect(s->vg, settings_btn_xr, settings_btn_y, settings_btn_w, settings_btn_h);
nvgFillPaint(s->vg, imgPaint);
nvgFill(s->vg);
}
static void ui_draw_sidebar_home_button(UIState *s, bool hasSidebar) {
bool homeActive = s->active_app == cereal_UiLayoutState_App_home;
const int home_btn_xr = hasSidebar ? home_btn_x : -(sbr_w);
nvgBeginPath(s->vg);
NVGpaint imgPaint = nvgImagePattern(s->vg, home_btn_xr, home_btn_y,
home_btn_w, home_btn_h, 0, s->img_button_home, homeActive ? 1.0f : 0.65f);
nvgRect(s->vg, home_btn_xr, home_btn_y, home_btn_w, home_btn_h);
nvgFillPaint(s->vg, imgPaint);
nvgFill(s->vg);
}
static void ui_draw_sidebar_network_strength(UIState *s, bool hasSidebar) {
const int network_img_h = 27;
const int network_img_w = 176;
const int network_img_x = hasSidebar ? 58 : -(sbr_w);
const int network_img_y = 196;
const int network_img = s->scene.networkType == cereal_ThermalData_NetworkType_none ?
s->img_network[0] : s->img_network[s->scene.networkStrength + 1];
nvgBeginPath(s->vg);
NVGpaint imgPaint = nvgImagePattern(s->vg, network_img_x, network_img_y,
network_img_w, network_img_h, 0, network_img, 1.0f);
nvgRect(s->vg, network_img_x, network_img_y, network_img_w, network_img_h);
nvgFillPaint(s->vg, imgPaint);
nvgFill(s->vg);
}
static void ui_draw_sidebar_battery_icon(UIState *s, bool hasSidebar) {
const int battery_img_h = 36;
const int battery_img_w = 76;
const int battery_img_x = hasSidebar ? 160 : -(sbr_w);
const int battery_img_y = 255;
int battery_img = strcmp(s->scene.batteryStatus, "Charging") == 0 ?
s->img_battery_charging : s->img_battery;
nvgBeginPath(s->vg);
nvgRect(s->vg, battery_img_x + 6, battery_img_y + 5,
((battery_img_w - 19) * (s->scene.batteryPercent * 0.01)), battery_img_h - 11);
nvgFillColor(s->vg, COLOR_WHITE);
nvgFill(s->vg);
nvgBeginPath(s->vg);
NVGpaint imgPaint = nvgImagePattern(s->vg, battery_img_x, battery_img_y,
battery_img_w, battery_img_h, 0, battery_img, 1.0f);
nvgRect(s->vg, battery_img_x, battery_img_y, battery_img_w, battery_img_h);
nvgFillPaint(s->vg, imgPaint);
nvgFill(s->vg);
}
static void ui_draw_sidebar_network_type(UIState *s, bool hasSidebar) {
const int network_x = hasSidebar ? 50 : -(sbr_w);
const int network_y = 273;
const int network_w = 100;
const int network_h = 100;
const char *network_types[6] = {"--", "WiFi", "2G", "3G", "4G", "5G"};
char network_type_str[32];
if (s->scene.networkType <= 5) {
snprintf(network_type_str, sizeof(network_type_str), "%s", network_types[s->scene.networkType]);
}
nvgFillColor(s->vg, COLOR_WHITE);
nvgFontSize(s->vg, 48);
nvgFontFace(s->vg, "sans-regular");
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
nvgTextBox(s->vg, network_x, network_y, network_w, network_type_str, NULL);
}
static void ui_draw_sidebar_metric(UIState *s, const char* label_str, const char* value_str, const int severity, const int y_offset, const char* message_str, bool hasSidebar) {
const int metric_x = hasSidebar ? 30 : -(sbr_w);
const int metric_y = 338 + y_offset;
const int metric_w = 240;
const int metric_h = message_str ? strlen(message_str) > 8 ? 124 : 100 : 148;
NVGcolor status_color;
if (severity == 0) {
status_color = COLOR_WHITE;
} else if (severity == 1) {
status_color = COLOR_YELLOW;
} else if (severity > 1) {
status_color = COLOR_RED;
}
nvgBeginPath(s->vg);
nvgRoundedRect(s->vg, metric_x, metric_y, metric_w, metric_h, 20);
nvgStrokeColor(s->vg, severity > 0 ? COLOR_WHITE : COLOR_WHITE_ALPHA);
nvgStrokeWidth(s->vg, 2);
nvgStroke(s->vg);
nvgBeginPath(s->vg);
nvgRoundedRectVarying(s->vg, metric_x + 6, metric_y + 6, 18, metric_h - 12, 25, 0, 0, 25);
nvgFillColor(s->vg, status_color);
nvgFill(s->vg);
if (!message_str) {
nvgFillColor(s->vg, COLOR_WHITE);
nvgFontSize(s->vg, 78);
nvgFontFace(s->vg, "sans-bold");
nvgTextAlign(s->vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
nvgTextBox(s->vg, metric_x + 50, metric_y + 50, metric_w - 60, value_str, NULL);
nvgFillColor(s->vg, COLOR_WHITE);
nvgFontSize(s->vg, 48);
nvgFontFace(s->vg, "sans-regular");
nvgTextAlign(s->vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
nvgTextBox(s->vg, metric_x + 50, metric_y + 50 + 66, metric_w - 60, label_str, NULL);
} else {
nvgFillColor(s->vg, COLOR_WHITE);
nvgFontSize(s->vg, 48);
nvgFontFace(s->vg, "sans-bold");
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
nvgTextBox(s->vg, metric_x + 35, metric_y + (strlen(message_str) > 8 ? 40 : 50), metric_w - 50, message_str, NULL);
}
}
static void ui_draw_sidebar_storage_metric(UIState *s, bool hasSidebar) {
int storage_severity;
char storage_label_str[32];
char storage_value_str[32];
char storage_value_unit[32];
const int storage_y_offset = 0;
const float storage_pct = ceilf((1.0 - s->scene.freeSpace) * 100);
if (storage_pct < 75.0) {
storage_severity = 0;
} else if (storage_pct >= 75.0 && storage_pct < 87.0) {
storage_severity = 1;
} else if (storage_pct >= 87.0) {
storage_severity = 2;
}
snprintf(storage_value_str, sizeof(storage_value_str), "%d", (int)storage_pct);
snprintf(storage_value_unit, sizeof(storage_value_unit), "%s", "%");
snprintf(storage_label_str, sizeof(storage_label_str), "%s", "STORAGE");
strcat(storage_value_str, storage_value_unit);
ui_draw_sidebar_metric(s, storage_label_str, storage_value_str, storage_severity, storage_y_offset, NULL, hasSidebar);
}
static void ui_draw_sidebar_temp_metric(UIState *s, bool hasSidebar) {
int temp_severity;
char temp_label_str[32];
char temp_value_str[32];
char temp_value_unit[32];
const int temp_y_offset = 148 + 32;
if (s->scene.thermalStatus == cereal_ThermalData_ThermalStatus_green) {
temp_severity = 0;
} else if (s->scene.thermalStatus == cereal_ThermalData_ThermalStatus_yellow) {
temp_severity = 1;
} else if (s->scene.thermalStatus == cereal_ThermalData_ThermalStatus_red) {
temp_severity = 2;
} else if (s->scene.thermalStatus == cereal_ThermalData_ThermalStatus_danger) {
temp_severity = 3;
}
snprintf(temp_value_str, sizeof(temp_value_str), "%d", s->scene.paTemp);
snprintf(temp_value_unit, sizeof(temp_value_unit), "%s", "°C");
snprintf(temp_label_str, sizeof(temp_label_str), "%s", "TEMP");
strcat(temp_value_str, temp_value_unit);
ui_draw_sidebar_metric(s, temp_label_str, temp_value_str, temp_severity, temp_y_offset, NULL, hasSidebar);
}
static void ui_draw_sidebar_panda_metric(UIState *s, bool hasSidebar) {
int panda_severity;
char panda_message_str[32];
const int panda_y_offset = (148 + 32) * 2;
if (s->scene.hwType == cereal_HealthData_HwType_unknown) {
panda_severity = 2;
snprintf(panda_message_str, sizeof(panda_message_str), "%s", "NO PANDA");
} else if (s->scene.hwType == cereal_HealthData_HwType_whitePanda) {
panda_severity = 0;
snprintf(panda_message_str, sizeof(panda_message_str), "%s", "PANDA ACTIVE");
} else if (
(s->scene.hwType == cereal_HealthData_HwType_greyPanda) ||
(s->scene.hwType == cereal_HealthData_HwType_blackPanda) ||
(s->scene.hwType == cereal_HealthData_HwType_uno)) {
if (s->scene.satelliteCount == -1) {
panda_severity = 0;
snprintf(panda_message_str, sizeof(panda_message_str), "%s", "PANDA ACTIVE");
} else if (s->scene.satelliteCount < 6) {
panda_severity = 1;
snprintf(panda_message_str, sizeof(panda_message_str), "%s", "PANDA\nNO GPS");
} else if (s->scene.satelliteCount >= 6) {
panda_severity = 0;
snprintf(panda_message_str, sizeof(panda_message_str), "%s", "PANDA GOOD GPS");
}
}
ui_draw_sidebar_metric(s, NULL, NULL, panda_severity, panda_y_offset, panda_message_str, hasSidebar);
}
void ui_draw_sidebar(UIState *s) {
bool hasSidebar = !s->scene.uilayout_sidebarcollapsed;
ui_draw_sidebar_background(s, hasSidebar);
ui_draw_sidebar_settings_button(s, hasSidebar);
ui_draw_sidebar_home_button(s, hasSidebar);
ui_draw_sidebar_network_strength(s, hasSidebar);
ui_draw_sidebar_battery_icon(s, hasSidebar);
ui_draw_sidebar_network_type(s, hasSidebar);
ui_draw_sidebar_storage_metric(s, hasSidebar);
ui_draw_sidebar_temp_metric(s, hasSidebar);
ui_draw_sidebar_panda_metric(s, hasSidebar);
}

@ -57,6 +57,45 @@ static void set_awake(UIState *s, bool awake) {
#endif #endif
} }
static void navigate_to_settings(UIState *s) {
#ifdef QCOM
system("am broadcast -a 'ai.comma.plus.SidebarSettingsTouchUpInside'");
#else
// computer UI doesn't have offroad settings
#endif
}
static void navigate_to_home(UIState *s) {
#ifdef QCOM
system("am broadcast -a 'ai.comma.plus.HomeButtonTouchUpInside'");
#else
// computer UI doesn't have offroad home
#endif
}
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)) {
navigate_to_settings(s);
}
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)) {
navigate_to_home(s);
if (s->vision_connected) {
s->scene.uilayout_sidebarcollapsed = true;
}
}
}
}
static void handle_vision_touch(UIState *s, int touch_x, int touch_y) {
if (s->vision_connected && (touch_x >= s->scene.ui_viz_rx - bdr_s)
&& (s->active_app != cereal_UiLayoutState_App_settings)) {
s->scene.uilayout_sidebarcollapsed = !s->scene.uilayout_sidebarcollapsed;
}
}
volatile sig_atomic_t do_exit = 0; volatile sig_atomic_t do_exit = 0;
static void set_do_exit(int sig) { static void set_do_exit(int sig) {
do_exit = 1; do_exit = 1;
@ -110,19 +149,28 @@ static void ui_init(UIState *s) {
s->uilayout_sock = SubSocket::create(s->ctx, "uiLayoutState"); s->uilayout_sock = SubSocket::create(s->ctx, "uiLayoutState");
s->livecalibration_sock = SubSocket::create(s->ctx, "liveCalibration"); s->livecalibration_sock = SubSocket::create(s->ctx, "liveCalibration");
s->radarstate_sock = SubSocket::create(s->ctx, "radarState"); s->radarstate_sock = SubSocket::create(s->ctx, "radarState");
s->thermal_sock = SubSocket::create(s->ctx, "thermal");
s->health_sock = SubSocket::create(s->ctx, "health");
s->ubloxgnss_sock = SubSocket::create(s->ctx, "ubloxGnss");
assert(s->model_sock != NULL); assert(s->model_sock != NULL);
assert(s->controlsstate_sock != NULL); assert(s->controlsstate_sock != NULL);
assert(s->uilayout_sock != NULL); assert(s->uilayout_sock != NULL);
assert(s->livecalibration_sock != NULL); assert(s->livecalibration_sock != NULL);
assert(s->radarstate_sock != NULL); assert(s->radarstate_sock != NULL);
assert(s->thermal_sock != NULL);
assert(s->health_sock != NULL);
assert(s->ubloxgnss_sock != NULL);
s->poller = Poller::create({ s->poller = Poller::create({
s->model_sock, s->model_sock,
s->controlsstate_sock, s->controlsstate_sock,
s->uilayout_sock, s->uilayout_sock,
s->livecalibration_sock, s->livecalibration_sock,
s->radarstate_sock s->radarstate_sock,
s->thermal_sock,
s->health_sock,
s->ubloxgnss_sock
}); });
#ifdef SHOW_SPEEDLIMIT #ifdef SHOW_SPEEDLIMIT
@ -404,27 +452,56 @@ void handle_message(UIState *s, Message * msg) {
cereal_read_UiLayoutState(&datad, eventd.uiLayoutState); cereal_read_UiLayoutState(&datad, eventd.uiLayoutState);
s->active_app = datad.activeApp; s->active_app = datad.activeApp;
s->scene.uilayout_sidebarcollapsed = datad.sidebarCollapsed; s->scene.uilayout_sidebarcollapsed = datad.sidebarCollapsed;
s->scene.uilayout_mapenabled = datad.mapEnabled;
bool hasSidebar = !s->scene.uilayout_sidebarcollapsed;
bool mapEnabled = s->scene.uilayout_mapenabled;
if (mapEnabled) {
s->scene.ui_viz_rx = hasSidebar ? (box_x+nav_w) : (box_x+nav_w-(bdr_s*4));
s->scene.ui_viz_rw = hasSidebar ? (box_w-nav_w) : (box_w-nav_w+(bdr_s*4));
s->scene.ui_viz_ro = -(sbr_w + 4*bdr_s);
} else {
s->scene.ui_viz_rx = hasSidebar ? box_x : (box_x-sbr_w+bdr_s*2);
s->scene.ui_viz_rw = hasSidebar ? box_w : (box_w+sbr_w-(bdr_s*2));
s->scene.ui_viz_ro = hasSidebar ? -(sbr_w - 6*bdr_s) : 0;
}
} else if (eventd.which == cereal_Event_liveMapData) { } else if (eventd.which == cereal_Event_liveMapData) {
struct cereal_LiveMapData datad; struct cereal_LiveMapData datad;
cereal_read_LiveMapData(&datad, eventd.liveMapData); cereal_read_LiveMapData(&datad, eventd.liveMapData);
s->scene.map_valid = datad.mapValid; s->scene.map_valid = datad.mapValid;
} else if (eventd.which == cereal_Event_thermal) {
struct cereal_ThermalData datad;
cereal_read_ThermalData(&datad, eventd.thermal);
s->scene.networkType = datad.networkType;
s->scene.networkStrength = datad.networkStrength;
s->scene.batteryPercent = datad.batteryPercent;
snprintf(s->scene.batteryStatus, sizeof(s->scene.batteryStatus), "%s", datad.batteryStatus.str);
s->scene.freeSpace = datad.freeSpace;
s->scene.thermalStatus = datad.thermalStatus;
s->scene.paTemp = datad.pa0;
} else if (eventd.which == cereal_Event_ubloxGnss) {
struct cereal_UbloxGnss datad;
cereal_read_UbloxGnss(&datad, eventd.ubloxGnss);
struct cereal_UbloxGnss_MeasurementReport reportdatad;
cereal_read_UbloxGnss_MeasurementReport(&reportdatad, datad.measurementReport);
s->scene.satelliteCount = reportdatad.numMeas;
} else if (eventd.which == cereal_Event_health) {
struct cereal_HealthData datad;
cereal_read_HealthData(&datad, eventd.health);
s->scene.hwType = datad.hwType;
s->hardware_timeout = 5*30; // 5 seconds at 30 fps
} }
capn_free(&ctx); capn_free(&ctx);
} }
static void check_messages(UIState *s) {
while(true) {
auto polls = s->poller->poll(0);
if (polls.size() == 0)
break;
for (auto sock : polls){
Message * msg = sock->receive();
if (msg == NULL) continue;
handle_message(s, msg);
delete msg;
}
}
}
static void ui_update(UIState *s) { static void ui_update(UIState *s) {
int err; int err;
@ -494,7 +571,7 @@ static void ui_update(UIState *s) {
assert(glGetError() == GL_NO_ERROR); assert(glGetError() == GL_NO_ERROR);
// Default UI Measurements (Assumes sidebar collapsed) s->scene.uilayout_sidebarcollapsed = true;
s->scene.ui_viz_rx = (box_x-sbr_w+bdr_s*2); s->scene.ui_viz_rx = (box_x-sbr_w+bdr_s*2);
s->scene.ui_viz_rw = (box_w+sbr_w-(bdr_s*2)); s->scene.ui_viz_rw = (box_w+sbr_w-(bdr_s*2));
s->scene.ui_viz_ro = 0; s->scene.ui_viz_ro = 0;
@ -575,23 +652,7 @@ static void ui_update(UIState *s) {
break; break;
} }
// peek and consume all events in the zmq queue, then return. // peek and consume all events in the zmq queue, then return.
while(true) { check_messages(s);
auto polls = s->poller->poll(0);
if (polls.size() == 0)
return;
for (auto sock : polls){
Message * msg = sock->receive();
if (msg == NULL) continue;
set_awake(s, true);
handle_message(s, msg);
delete msg;
}
}
} }
static int vision_subscribe(int fd, VisionPacket *rp, VisionStreamType type) { static int vision_subscribe(int fd, VisionPacket *rp, VisionStreamType type) {
@ -732,7 +793,6 @@ fail:
return NULL; return NULL;
} }
static void* bg_thread(void* args) { static void* bg_thread(void* args) {
UIState *s = (UIState*)args; UIState *s = (UIState*)args;
set_thread_name("bg"); set_thread_name("bg");
@ -813,7 +873,6 @@ int main(int argc, char* argv[]) {
TouchState touch = {0}; TouchState touch = {0};
touch_init(&touch); touch_init(&touch);
s->touch_fd = touch.fd; s->touch_fd = touch.fd;
ui_sound_init(); ui_sound_init();
// light sensor scaling params // light sensor scaling params
@ -830,6 +889,9 @@ int main(int argc, char* argv[]) {
set_volume(MIN_VOLUME); set_volume(MIN_VOLUME);
s->volume_timeout = 5 * UI_FREQ; s->volume_timeout = 5 * UI_FREQ;
int draws = 0; int draws = 0;
s->scene.satelliteCount = -1;
while (!do_exit) { while (!do_exit) {
bool should_swap = false; bool should_swap = false;
if (!s->vision_connected) { if (!s->vision_connected) {
@ -847,34 +909,37 @@ int main(int argc, char* argv[]) {
if (smooth_brightness > 255) smooth_brightness = 255; if (smooth_brightness > 255) smooth_brightness = 255;
set_brightness(s, (int)smooth_brightness); set_brightness(s, (int)smooth_brightness);
// resize vision for collapsing sidebar
const bool hasSidebar = !s->scene.uilayout_sidebarcollapsed;
s->scene.ui_viz_rx = hasSidebar ? box_x : (box_x - sbr_w + (bdr_s * 2));
s->scene.ui_viz_rw = hasSidebar ? box_w : (box_w + sbr_w - (bdr_s * 2));
s->scene.ui_viz_ro = hasSidebar ? -(sbr_w - 6 * bdr_s) : 0;
// 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);
}
if (!s->vision_connected) { if (!s->vision_connected) {
// Car is not started, keep in idle state and awake on touch events
zmq_pollitem_t polls[1] = {{0}};
polls[0].fd = s->touch_fd;
polls[0].events = ZMQ_POLLIN;
int ret = zmq_poll(polls, 1, 0);
if (ret < 0){
if (errno == EINTR) continue;
LOGW("poll failed (%d)", ret);
} else if (ret > 0) {
// awake on any touch
int touch_x = -1, touch_y = -1;
int touched = touch_read(&touch, &touch_x, &touch_y);
if (touched == 1) {
set_awake(s, true);
}
}
if (s->status != STATUS_STOPPED) { if (s->status != STATUS_STOPPED) {
update_status(s, STATUS_STOPPED); update_status(s, STATUS_STOPPED);
} }
check_messages(s);
} else { } else {
set_awake(s, true);
if (s->status == STATUS_STOPPED) { if (s->status == STATUS_STOPPED) {
update_status(s, STATUS_DISENGAGED); update_status(s, STATUS_DISENGAGED);
} }
// Car started, fetch a new rgb image from ipc and peek for zmq events. // Car started, fetch a new rgb image from ipc and peek for zmq events.
ui_update(s); ui_update(s);
if(!s->vision_connected) { if (!s->vision_connected) {
// Visiond process is just stopped, force a redraw to make screen blank again. // Visiond process is just stopped, force a redraw to make screen blank again.
s->scene.satelliteCount = -1;
s->scene.uilayout_sidebarcollapsed = false;
ui_draw(s); ui_draw(s);
glFinish(); glFinish();
should_swap = true; should_swap = true;
@ -888,8 +953,15 @@ int main(int argc, char* argv[]) {
set_awake(s, false); set_awake(s, false);
} }
// Don't waste resources on drawing in case screen is off or car is not started. // manage hardware disconnect
if (s->awake && s->vision_connected) { if (s->hardware_timeout > 0) {
s->hardware_timeout--;
} else {
s->scene.hwType = cereal_HealthData_HwType_unknown;
}
// Don't waste resources on drawing in case screen is off
if (s->awake) {
ui_draw(s); ui_draw(s);
glFinish(); glFinish();
should_swap = true; should_swap = true;

@ -38,6 +38,12 @@
#define ALERTSIZE_MID 2 #define ALERTSIZE_MID 2
#define ALERTSIZE_FULL 3 #define ALERTSIZE_FULL 3
#define COLOR_BLACK_ALPHA nvgRGBA(0, 0, 0, 85)
#define COLOR_WHITE nvgRGBA(255, 255, 255, 255)
#define COLOR_WHITE_ALPHA nvgRGBA(255, 255, 255, 85)
#define COLOR_YELLOW nvgRGBA(218, 202, 37, 255)
#define COLOR_RED nvgRGBA(201, 34, 49, 255)
#ifndef QCOM #ifndef QCOM
#define UI_60FPS #define UI_60FPS
#endif #endif
@ -60,6 +66,14 @@ const int viz_w = vwp_w-(bdr_s*2);
const int header_h = 420; const int header_h = 420;
const int footer_h = 280; const int footer_h = 280;
const int footer_y = vwp_h-bdr_s-footer_h; const int footer_y = vwp_h-bdr_s-footer_h;
const int settings_btn_h = 117;
const int settings_btn_w = 200;
const int settings_btn_x = 50;
const int settings_btn_y = 35;
const int home_btn_h = 180;
const int home_btn_w = 180;
const int home_btn_x = 60;
const int home_btn_y = vwp_h - home_btn_h - 40;
const int UI_FREQ = 30; // Hz const int UI_FREQ = 30; // Hz
@ -115,7 +129,7 @@ typedef struct UIScene {
int lead_status; int lead_status;
float lead_d_rel, lead_y_rel, lead_v_rel; float lead_d_rel, lead_y_rel, lead_v_rel;
int lead_status2; int lead_status2;
float lead_d_rel2, lead_y_rel2, lead_v_rel2; float lead_d_rel2, lead_y_rel2, lead_v_rel2;
@ -131,6 +145,16 @@ typedef struct UIScene {
// Used to show gps planner status // Used to show gps planner status
bool gps_planner_active; bool gps_planner_active;
uint8_t networkType;
uint8_t networkStrength;
int batteryPercent;
char batteryStatus[64];
float freeSpace;
uint8_t thermalStatus;
int paTemp;
int hwType;
int satelliteCount;
} UIScene; } UIScene;
typedef struct { typedef struct {
@ -168,6 +192,11 @@ typedef struct UIState {
int img_turn; int img_turn;
int img_face; int img_face;
int img_map; int img_map;
int img_button_settings;
int img_button_home;
int img_battery;
int img_battery_charging;
int img_network[6];
// sockets // sockets
Context *ctx; Context *ctx;
@ -177,7 +206,11 @@ typedef struct UIState {
SubSocket *radarstate_sock; SubSocket *radarstate_sock;
SubSocket *map_data_sock; SubSocket *map_data_sock;
SubSocket *uilayout_sock; SubSocket *uilayout_sock;
SubSocket *thermal_sock;
SubSocket *health_sock;
SubSocket *ubloxgnss_sock;
Poller * poller; Poller * poller;
Poller * ublox_poller;
int active_app; int active_app;
@ -221,6 +254,7 @@ typedef struct UIState {
int is_metric_timeout; int is_metric_timeout;
int longitudinal_control_timeout; int longitudinal_control_timeout;
int limit_set_speed_timeout; int limit_set_speed_timeout;
int hardware_timeout;
bool controls_seen; bool controls_seen;
@ -254,8 +288,9 @@ typedef struct UIState {
// API // API
void ui_draw_vision_alert(UIState *s, int va_size, int va_color, void ui_draw_vision_alert(UIState *s, int va_size, int va_color,
const char* va_text1, const char* va_text2); const char* va_text1, const char* va_text2);
void ui_draw(UIState *s); void ui_draw(UIState *s);
void ui_draw_sidebar(UIState *s);
void ui_nvg_init(UIState *s); void ui_nvg_init(UIState *s);
#endif #endif

Loading…
Cancel
Save