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 sidebaralbatross
BIN
apk/ai.comma.plus.black.apk (Stored with Git LFS)
BIN
apk/ai.comma.plus.frame.apk (Stored with Git LFS)
BIN
apk/ai.comma.plus.offroad.apk (Stored with Git LFS)
|
@ -6,7 +6,7 @@ import shutil
|
|||
from common.basedir import BASEDIR
|
||||
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():
|
||||
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)
|
||||
return ret == 0
|
||||
|
||||
def start_frame():
|
||||
def start_offroad():
|
||||
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():
|
||||
pm_grant("ai.comma.plus.offroad", "android.permission.ACCESS_FINE_LOCATION")
|
||||
|
@ -95,4 +95,3 @@ def pm_apply_packages(cmd):
|
|||
|
||||
if __name__ == "__main__":
|
||||
update_apks()
|
||||
|
||||
|
|
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 957 B |
After Width: | Height: | Size: 416 B |
After Width: | Height: | Size: 462 B |
After Width: | Height: | Size: 593 B |
After Width: | Height: | Size: 524 B |
After Width: | Height: | Size: 541 B |
After Width: | Height: | Size: 503 B |
|
@ -129,7 +129,7 @@ from selfdrive.version import version, dirty
|
|||
from selfdrive.loggerd.config import ROOT
|
||||
from selfdrive.launcher import launcher
|
||||
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
|
||||
|
||||
ThermalStatus = cereal.log.ThermalData.ThermalStatus
|
||||
|
@ -406,10 +406,10 @@ def manager_thread():
|
|||
for p in persistent_processes:
|
||||
start_managed_process(p)
|
||||
|
||||
# start frame
|
||||
# start offroad
|
||||
if ANDROID:
|
||||
pm_apply_packages('enable')
|
||||
start_frame()
|
||||
start_offroad()
|
||||
|
||||
if os.getenv("NOBOARD") is None:
|
||||
start_managed_process("pandad")
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import os
|
||||
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.testing import phone_only
|
||||
from selfdrive.manager import manager_init, manager_prepare
|
||||
|
@ -57,7 +57,7 @@ def with_apks():
|
|||
|
||||
update_apks()
|
||||
pm_apply_packages('enable')
|
||||
start_frame()
|
||||
start_offroad()
|
||||
|
||||
func()
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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]
|
||||
|
||||
if arch == "aarch64":
|
||||
|
|
|
@ -877,6 +877,7 @@ static void ui_draw_blank(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) {
|
||||
ui_draw_vision(s);
|
||||
} else {
|
||||
|
@ -985,6 +986,25 @@ void ui_nvg_init(UIState *s) {
|
|||
assert(s->img_map >= 0);
|
||||
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
|
||||
s->frame_program = load_program(frame_vertex_shader, frame_fragment_shader);
|
||||
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
|
||||
}
|
||||
|
||||
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;
|
||||
static void set_do_exit(int sig) {
|
||||
do_exit = 1;
|
||||
|
@ -110,19 +149,28 @@ static void ui_init(UIState *s) {
|
|||
s->uilayout_sock = SubSocket::create(s->ctx, "uiLayoutState");
|
||||
s->livecalibration_sock = SubSocket::create(s->ctx, "liveCalibration");
|
||||
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->controlsstate_sock != NULL);
|
||||
assert(s->uilayout_sock != NULL);
|
||||
assert(s->livecalibration_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->model_sock,
|
||||
s->controlsstate_sock,
|
||||
s->uilayout_sock,
|
||||
s->livecalibration_sock,
|
||||
s->radarstate_sock
|
||||
s->radarstate_sock,
|
||||
s->thermal_sock,
|
||||
s->health_sock,
|
||||
s->ubloxgnss_sock
|
||||
});
|
||||
|
||||
#ifdef SHOW_SPEEDLIMIT
|
||||
|
@ -404,27 +452,56 @@ void handle_message(UIState *s, Message * msg) {
|
|||
cereal_read_UiLayoutState(&datad, eventd.uiLayoutState);
|
||||
s->active_app = datad.activeApp;
|
||||
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) {
|
||||
struct cereal_LiveMapData datad;
|
||||
cereal_read_LiveMapData(&datad, eventd.liveMapData);
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
int err;
|
||||
|
||||
|
@ -494,7 +571,7 @@ static void ui_update(UIState *s) {
|
|||
|
||||
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_rw = (box_w+sbr_w-(bdr_s*2));
|
||||
s->scene.ui_viz_ro = 0;
|
||||
|
@ -575,23 +652,7 @@ static void ui_update(UIState *s) {
|
|||
break;
|
||||
}
|
||||
// peek and consume all events in the zmq queue, then return.
|
||||
while(true) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
check_messages(s);
|
||||
}
|
||||
|
||||
static int vision_subscribe(int fd, VisionPacket *rp, VisionStreamType type) {
|
||||
|
@ -732,7 +793,6 @@ fail:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void* bg_thread(void* args) {
|
||||
UIState *s = (UIState*)args;
|
||||
set_thread_name("bg");
|
||||
|
@ -813,7 +873,6 @@ int main(int argc, char* argv[]) {
|
|||
TouchState touch = {0};
|
||||
touch_init(&touch);
|
||||
s->touch_fd = touch.fd;
|
||||
|
||||
ui_sound_init();
|
||||
|
||||
// light sensor scaling params
|
||||
|
@ -830,6 +889,9 @@ int main(int argc, char* argv[]) {
|
|||
set_volume(MIN_VOLUME);
|
||||
s->volume_timeout = 5 * UI_FREQ;
|
||||
int draws = 0;
|
||||
|
||||
s->scene.satelliteCount = -1;
|
||||
|
||||
while (!do_exit) {
|
||||
bool should_swap = false;
|
||||
if (!s->vision_connected) {
|
||||
|
@ -847,34 +909,37 @@ int main(int argc, char* argv[]) {
|
|||
if (smooth_brightness > 255) smooth_brightness = 255;
|
||||
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) {
|
||||
// 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) {
|
||||
update_status(s, STATUS_STOPPED);
|
||||
}
|
||||
check_messages(s);
|
||||
} else {
|
||||
set_awake(s, true);
|
||||
if (s->status == STATUS_STOPPED) {
|
||||
update_status(s, STATUS_DISENGAGED);
|
||||
}
|
||||
// Car started, fetch a new rgb image from ipc and peek for zmq events.
|
||||
ui_update(s);
|
||||
if(!s->vision_connected) {
|
||||
if (!s->vision_connected) {
|
||||
// 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);
|
||||
glFinish();
|
||||
should_swap = true;
|
||||
|
@ -888,8 +953,15 @@ int main(int argc, char* argv[]) {
|
|||
set_awake(s, false);
|
||||
}
|
||||
|
||||
// Don't waste resources on drawing in case screen is off or car is not started.
|
||||
if (s->awake && s->vision_connected) {
|
||||
// manage hardware disconnect
|
||||
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);
|
||||
glFinish();
|
||||
should_swap = true;
|
||||
|
|
|
@ -38,6 +38,12 @@
|
|||
#define ALERTSIZE_MID 2
|
||||
#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
|
||||
#define UI_60FPS
|
||||
#endif
|
||||
|
@ -60,6 +66,14 @@ const int viz_w = vwp_w-(bdr_s*2);
|
|||
const int header_h = 420;
|
||||
const int footer_h = 280;
|
||||
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
|
||||
|
||||
|
@ -115,7 +129,7 @@ typedef struct UIScene {
|
|||
|
||||
int lead_status;
|
||||
float lead_d_rel, lead_y_rel, lead_v_rel;
|
||||
|
||||
|
||||
int lead_status2;
|
||||
float lead_d_rel2, lead_y_rel2, lead_v_rel2;
|
||||
|
||||
|
@ -131,6 +145,16 @@ typedef struct UIScene {
|
|||
|
||||
// Used to show gps planner status
|
||||
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;
|
||||
|
||||
typedef struct {
|
||||
|
@ -168,6 +192,11 @@ typedef struct UIState {
|
|||
int img_turn;
|
||||
int img_face;
|
||||
int img_map;
|
||||
int img_button_settings;
|
||||
int img_button_home;
|
||||
int img_battery;
|
||||
int img_battery_charging;
|
||||
int img_network[6];
|
||||
|
||||
// sockets
|
||||
Context *ctx;
|
||||
|
@ -177,7 +206,11 @@ typedef struct UIState {
|
|||
SubSocket *radarstate_sock;
|
||||
SubSocket *map_data_sock;
|
||||
SubSocket *uilayout_sock;
|
||||
SubSocket *thermal_sock;
|
||||
SubSocket *health_sock;
|
||||
SubSocket *ubloxgnss_sock;
|
||||
Poller * poller;
|
||||
Poller * ublox_poller;
|
||||
|
||||
int active_app;
|
||||
|
||||
|
@ -221,6 +254,7 @@ typedef struct UIState {
|
|||
int is_metric_timeout;
|
||||
int longitudinal_control_timeout;
|
||||
int limit_set_speed_timeout;
|
||||
int hardware_timeout;
|
||||
|
||||
bool controls_seen;
|
||||
|
||||
|
@ -254,8 +288,9 @@ typedef struct UIState {
|
|||
|
||||
// API
|
||||
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_sidebar(UIState *s);
|
||||
void ui_nvg_init(UIState *s);
|
||||
|
||||
#endif
|
||||
|
|