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
pull/1097/head
Andrew Valish 5 years ago committed by GitHub
parent 8eff974a41
commit 5ba6beed17
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  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. BIN
      selfdrive/assets/images/battery.png
  6. BIN
      selfdrive/assets/images/battery_charging.png
  7. BIN
      selfdrive/assets/images/button_home.png
  8. BIN
      selfdrive/assets/images/button_settings.png
  9. BIN
      selfdrive/assets/images/network_0.png
  10. BIN
      selfdrive/assets/images/network_1.png
  11. BIN
      selfdrive/assets/images/network_2.png
  12. BIN
      selfdrive/assets/images/network_3.png
  13. BIN
      selfdrive/assets/images/network_4.png
  14. BIN
      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. 172
      selfdrive/ui/ui.cc
  21. 35
      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()

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 B

@ -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);
if (!s->vision_connected) { // resize vision for collapsing sidebar
// Car is not started, keep in idle state and awake on touch events const bool hasSidebar = !s->scene.uilayout_sidebarcollapsed;
zmq_pollitem_t polls[1] = {{0}}; s->scene.ui_viz_rx = hasSidebar ? box_x : (box_x - sbr_w + (bdr_s * 2));
polls[0].fd = s->touch_fd; s->scene.ui_viz_rw = hasSidebar ? box_w : (box_w + sbr_w - (bdr_s * 2));
polls[0].events = ZMQ_POLLIN; s->scene.ui_viz_ro = hasSidebar ? -(sbr_w - 6 * bdr_s) : 0;
int ret = zmq_poll(polls, 1, 0);
if (ret < 0){ // poll for touch events
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 touch_x = -1, touch_y = -1;
int touched = touch_read(&touch, &touch_x, &touch_y); int touched = touch_poll(&touch, &touch_x, &touch_y, 0);
if (touched == 1) { if (touched == 1) {
set_awake(s, true); 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->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
@ -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;
@ -256,6 +290,7 @@ typedef struct UIState {
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