UI vision refactor (#2115)

* refactor vision

* don't show slow frame message when in preview mode

* change draws to uint32_t

* set vision_seen=false after destroy

* remove vision_connect_thread

* refactor ui_update

* seelp 30ms when vision is not connected

* remove should_swap

* call ui_update_sizes before ui_draw

* rebase

* start bigger UI refactor

* don't need the touch fd

* fix qt build

* more cleanup

* more responsive

* more refactor

* fix for pc

* poll for frames

* lower CPU usage

* cleanup

* no more zmq

* undo that

* cleanup speed limit

* fix sidebar severity for athena status

* not aarch64

Co-authored-by: deanlee <deanlee3@gmail.com>
Co-authored-by: Comma Device <device@comma.ai>
Co-authored-by: Willem Melching <willem.melching@gmail.com>
old-commit-hash: 848301b091
commatwo_master
Adeeb Shihadeh 5 years ago committed by GitHub
parent 9788cf1ed3
commit c3f623e432
  1. 1
      common/params.py
  2. 1
      selfdrive/controls/controlsd.py
  3. 1
      selfdrive/manager.py
  4. 2
      selfdrive/test/test_cpu_usage.py
  5. 125
      selfdrive/ui/android_ui.cc
  6. 86
      selfdrive/ui/paint.cc
  7. 17
      selfdrive/ui/qt/window.cc
  8. 1
      selfdrive/ui/qt/window.hpp
  9. 14
      selfdrive/ui/sidebar.cc
  10. 413
      selfdrive/ui/ui.cc
  11. 125
      selfdrive/ui/ui.hpp

@ -85,7 +85,6 @@ keys = {
"LimitSetSpeed": [TxType.PERSISTENT],
"LimitSetSpeedNeural": [TxType.PERSISTENT],
"LiveParameters": [TxType.PERSISTENT],
"LongitudinalControl": [TxType.PERSISTENT],
"OpenpilotEnabledToggle": [TxType.PERSISTENT],
"LaneChangeEnabled": [TxType.PERSISTENT],
"PandaFirmware": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT],

@ -94,7 +94,6 @@ class Controls:
cp_bytes = self.CP.to_bytes()
params.put("CarParams", cp_bytes)
put_nonblocking("CarParamsCache", cp_bytes)
put_nonblocking("LongitudinalControl", "1" if self.CP.openpilotLongitudinalControl else "0")
self.CC = car.CarControl.new_message()
self.AM = AlertManager()

@ -571,7 +571,6 @@ def main():
("IsUploadRawEnabled", "1"),
("IsLdwEnabled", "1"),
("IsGeofenceEnabled", "-1"),
("LongitudinalControl", "0"),
("LimitSetSpeed", "0"),
("LimitSetSpeedNeural", "0"),
("LastUpdateTime", datetime.datetime.utcnow().isoformat().encode('utf8')),

@ -22,10 +22,10 @@ def print_cpu_usage(first_proc, last_proc):
("selfdrive.locationd.paramsd", 11.53),
("./_modeld", 7.12),
("selfdrive.controls.radard", 9.54),
("./_ui", 9.54),
("./camerad", 7.07),
("./_sensord", 6.17),
("selfdrive.locationd.calibrationd", 6.0),
("./_ui", 5.82),
("./boardd", 3.63),
("./_dmonitoringmodeld", 2.67),
("selfdrive.logmessaged", 2.71),

@ -1,7 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/resource.h>
#include <czmq.h>
#include "common/util.h"
#include "common/utilpp.h"
@ -130,8 +130,7 @@ static void handle_sidebar_touch(UIState *s, int touch_x, int touch_y) {
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)
} 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;
@ -169,7 +168,6 @@ int main(int argc, char* argv[]) {
int err;
setpriority(PRIO_PROCESS, 0, -14);
zsys_handler_set(NULL);
signal(SIGINT, (sighandler_t)set_do_exit);
UIState uistate = {};
@ -179,12 +177,6 @@ int main(int argc, char* argv[]) {
enable_event_processing(true);
PubMaster *pm = new PubMaster({"offroadLayout"});
pthread_t connect_thread_handle;
err = pthread_create(&connect_thread_handle, NULL,
vision_connect_thread, s);
assert(err == 0);
pthread_t light_sensor_thread_handle;
err = pthread_create(&light_sensor_thread_handle, NULL,
light_sensor_thread, s);
@ -192,47 +184,33 @@ int main(int argc, char* argv[]) {
TouchState touch = {0};
touch_init(&touch);
s->touch_fd = touch.fd;
// light sensor scaling params
// 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;
assert(s->sound.init(MIN_VOLUME));
int draws = 0;
while (!do_exit) {
bool should_swap = false;
if (!s->started) {
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.
// Don't hold the lock while sleeping, so that vision_connect_thread have chances to get the lock.
usleep(30 * 1000);
}
pthread_mutex_lock(&s->lock);
double u1 = millis_since_boot();
// light sensor is only exposed on EONs
float clipped_brightness = (s->light_sensor*brightness_m) + brightness_b;
if (clipped_brightness > 512) clipped_brightness = 512;
smooth_brightness = clipped_brightness * 0.01 + smooth_brightness * 0.99;
if (smooth_brightness > 255) smooth_brightness = 255;
ui_set_brightness(s, (int)smooth_brightness);
ui_update_sizes(s);
ui_update(s);
// poll for touch events
int touch_x = -1, touch_y = -1;
@ -243,109 +221,44 @@ int main(int argc, char* argv[]) {
handle_vision_touch(s, touch_x, touch_y);
}
if (!s->started) {
// always process events offroad
check_messages(s);
} else {
// manage wakefulness
if (s->started) {
set_awake(s, true);
// Car started, fetch a new rgb image from ipc
if (s->vision_connected){
ui_update(s);
}
check_messages(s);
// Visiond process is just stopped, force a redraw to make screen blank again.
if (!s->started) {
s->scene.uilayout_sidebarcollapsed = false;
ui_draw(s);
glFinish();
should_swap = true;
}
}
// manage wakefulness
if (s->awake_timeout > 0) {
s->awake_timeout--;
} else {
set_awake(s, false);
}
// manage hardware disconnect
if ((s->sm->frame - s->sm->rcv_frame("health")) > 5*UI_FREQ) {
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;
if (!s->awake) {
continue;
}
s->sound.setVolume(fmin(MAX_VOLUME, MIN_VOLUME + s->scene.controls_state.getVEgo() / 5)); // up one notch every 5 m/s
bool controls_timeout = (s->sm->frame - s->sm->rcv_frame("controlsState")) > 5*UI_FREQ;
if (s->started && !s->scene.frontview && controls_timeout) {
if (!s->controls_seen) {
// car is started, but controlsState hasn't been seen at all
s->scene.alert_text1 = "openpilot Unavailable";
s->scene.alert_text2 = "Waiting for controls to start";
s->scene.alert_size = cereal::ControlsState::AlertSize::MID;
} else {
// car is started, but controls is lagging or died
LOGE("Controls unresponsive");
if (s->scene.alert_text2 != "Controls Unresponsive") {
s->sound.play(AudibleAlert::CHIME_WARNING_REPEAT);
}
s->scene.alert_text1 = "TAKE CONTROL IMMEDIATELY";
s->scene.alert_text2 = "Controls Unresponsive";
s->scene.alert_size = cereal::ControlsState::AlertSize::FULL;
update_status(s, STATUS_ALERT);
}
ui_draw_vision_alert(s, s->scene.alert_size, s->status, s->scene.alert_text1.c_str(), s->scene.alert_text2.c_str());
}
// 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);
if (s->sm->frame % (2*UI_FREQ) == 0) {
read_param(&s->is_metric, "IsMetric");
} else if (s->sm->frame % (3*UI_FREQ) == 0) {
int param_read = read_param(&s->last_athena_ping, "LastAthenaPingTime");
if (param_read != 0) { // Failed to read param
s->scene.athenaStatus = NET_DISCONNECTED;
} else if (nanos_since_boot() - s->last_athena_ping < 70e9) {
s->scene.athenaStatus = NET_CONNECTED;
} else {
s->scene.athenaStatus = NET_ERROR;
}
}
update_offroad_layout_state(s, pm);
pthread_mutex_unlock(&s->lock);
// the bg thread needs to be scheduled, so the main thread needs time without the lock
// safe to do this outside the lock?
if (should_swap) {
ui_draw(s);
double u2 = millis_since_boot();
if (u2-u1 > 66) {
if (!s->scene.frontview && (u2-u1 > 66)) {
// warn on sub 15fps
LOGW("slow frame(%d) time: %.2f", draws, u2-u1);
LOGW("slow frame(%llu) time: %.2f", (s->sm)->frame, u2-u1);
}
draws++;
framebuffer_swap(s->fb);
}
}
set_awake(s, true);
// wake up bg thread to exit
pthread_mutex_lock(&s->lock);
pthread_mutex_unlock(&s->lock);
// join light_sensor_thread?
err = pthread_join(connect_thread_handle, NULL);
err = pthread_join(light_sensor_thread_handle, NULL);
assert(err == 0);
delete s->sm;
delete pm;

@ -24,7 +24,7 @@ const mat3 intrinsic_matrix = (mat3){{
}};
const uint8_t alert_colors[][4] = {
[STATUS_STOPPED] = {0x07, 0x23, 0x39, 0xf1},
[STATUS_OFFROAD] = {0x07, 0x23, 0x39, 0xf1},
[STATUS_DISENGAGED] = {0x17, 0x33, 0x49, 0xc8},
[STATUS_ENGAGED] = {0x17, 0x86, 0x44, 0xf1},
[STATUS_WARNING] = {0xDA, 0x6F, 0x25, 0xf1},
@ -224,9 +224,9 @@ static void ui_draw_track(UIState *s, bool is_mpc, track_vertices_data *pvd) {
NVGpaint track_bg;
if (is_mpc) {
// Draw colored MPC track
const uint8_t *clr = bg_colors[s->status];
const Color clr = bg_colors[s->status];
track_bg = nvgLinearGradient(s->vg, vwp_w, vwp_h, vwp_w, vwp_h*.4,
nvgRGBA(clr[0], clr[1], clr[2], 255), nvgRGBA(clr[0], clr[1], clr[2], 255/2));
nvgRGBA(clr.r, clr.g, clr.b, 255), nvgRGBA(clr.r, clr.g, clr.b, 255/2));
} else {
// Draw white vision track
track_bg = nvgLinearGradient(s->vg, vwp_w, vwp_h, vwp_w, vwp_h*.4,
@ -237,29 +237,22 @@ static void ui_draw_track(UIState *s, bool is_mpc, track_vertices_data *pvd) {
}
static void draw_frame(UIState *s) {
const UIScene *scene = &s->scene;
mat4 *out_mat;
if (s->scene.frontview) {
glBindVertexArray(s->frame_vao[1]);
} else {
glBindVertexArray(s->frame_vao[0]);
}
mat4 *out_mat;
if (s->scene.frontview || s->scene.fullview) {
out_mat = &s->front_frame_mat;
} else {
glBindVertexArray(s->frame_vao[0]);
out_mat = &s->rear_frame_mat;
}
glActiveTexture(GL_TEXTURE0);
if (s->scene.frontview && s->cur_vision_front_idx >= 0) {
glBindTexture(GL_TEXTURE_2D, s->frame_front_texs[s->cur_vision_front_idx]);
} else if (!scene->frontview && s->cur_vision_idx >= 0) {
glBindTexture(GL_TEXTURE_2D, s->frame_texs[s->cur_vision_idx]);
// TODO: a better way to do this?
#ifndef QCOM
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, s->rgb_width, s->rgb_height, 0, GL_RGB, GL_UNSIGNED_BYTE, s->priv_hnds[s->cur_vision_idx]);
if (s->stream.last_idx >= 0) {
glBindTexture(GL_TEXTURE_2D, s->frame_texs[s->stream.last_idx]);
#ifndef __aarch64__
// this is handled in ion on QCOM
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, s->stream.bufs_info.width, s->stream.bufs_info.height,
0, GL_RGB, GL_UNSIGNED_BYTE, s->priv_hnds[s->stream.last_idx]);
#endif
}
@ -275,7 +268,7 @@ static void draw_frame(UIState *s) {
}
static inline bool valid_frame_pt(UIState *s, float x, float y) {
return x >= 0 && x <= s->rgb_width && y >= 0 && y <= s->rgb_height;
return x >= 0 && x <= s->stream.bufs_info.width && y >= 0 && y <= s->stream.bufs_info.height;
}
static void update_lane_line_data(UIState *s, const float *points, float off, model_path_vertices_data *pvd, float valid_len) {
@ -325,14 +318,10 @@ static void ui_draw_vision_lanes(UIState *s) {
}
// Draw left lane edge
ui_draw_lane(
s, pvd,
nvgRGBAf(1.0, 1.0, 1.0, scene->model.getLeftLane().getProb()));
ui_draw_lane(s, pvd, nvgRGBAf(1.0, 1.0, 1.0, scene->model.getLeftLane().getProb()));
// Draw right lane edge
ui_draw_lane(
s, pvd + MODEL_LANE_PATH_CNT,
nvgRGBAf(1.0, 1.0, 1.0, scene->model.getRightLane().getProb()));
ui_draw_lane(s, pvd + MODEL_LANE_PATH_CNT, nvgRGBAf(1.0, 1.0, 1.0, scene->model.getRightLane().getProb()));
if(s->sm->updated("radarState")) {
update_all_track_data(s);
@ -369,7 +358,7 @@ static void ui_draw_world(UIState *s) {
nvgTranslate(s->vg, -w / 2, -1080.0f / 2);
nvgScale(s->vg, 2.0, 2.0);
nvgScale(s->vg, w / s->rgb_width, 1080.0f / s->rgb_height);
nvgScale(s->vg, w / s->stream.bufs_info.width, 1080.0f / s->stream.bufs_info.height);
// Draw lane edges and vision/mpc tracks
ui_draw_vision_lanes(s);
@ -390,17 +379,11 @@ static void ui_draw_vision_maxspeed(UIState *s) {
char maxspeed_str[32];
float maxspeed = s->scene.controls_state.getVCruise();
int maxspeed_calc = maxspeed * 0.6225 + 0.5;
float speedlimit = s->scene.speedlimit;
int speedlim_calc = speedlimit * 2.2369363 + 0.5;
if (s->is_metric) {
maxspeed_calc = maxspeed + 0.5;
speedlim_calc = speedlimit * 3.6 + 0.5;
}
bool is_cruise_set = (maxspeed != 0 && maxspeed != SET_SPEED_NA);
bool is_speedlim_valid = s->scene.speedlimit_valid;
bool is_set_over_limit = is_speedlim_valid && s->scene.controls_state.getEnabled() &&
is_cruise_set && maxspeed_calc > speedlim_calc;
int viz_maxspeed_w = 184;
int viz_maxspeed_h = 202;
@ -411,17 +394,10 @@ static void ui_draw_vision_maxspeed(UIState *s) {
viz_maxspeed_xo = 0;
// Draw Background
ui_draw_rect(s->vg, viz_maxspeed_x, viz_maxspeed_y, viz_maxspeed_w, viz_maxspeed_h,
is_set_over_limit ? nvgRGBA(218, 111, 37, 180) : COLOR_BLACK_ALPHA(100), 30);
ui_draw_rect(s->vg, viz_maxspeed_x, viz_maxspeed_y, viz_maxspeed_w, viz_maxspeed_h, COLOR_BLACK_ALPHA(100), 30);
// Draw Border
NVGcolor color = COLOR_WHITE_ALPHA(100);
if (is_set_over_limit) {
color = COLOR_OCHRE;
} else if (is_speedlim_valid) {
color = s->is_ego_over_limit ? COLOR_WHITE_ALPHA(20) : COLOR_WHITE;
}
ui_draw_rect(s->vg, viz_maxspeed_x, viz_maxspeed_y, viz_maxspeed_w, viz_maxspeed_h, color, 20, 10);
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE);
@ -549,10 +525,10 @@ static void ui_draw_vision_header(UIState *s) {
(box_y+(header_h-(header_h/2.5))),
ui_viz_rx, box_y+header_h,
nvgRGBAf(0,0,0,0.45), nvgRGBAf(0,0,0,0));
ui_draw_rect(s->vg, ui_viz_rx, box_y, ui_viz_rw, header_h, gradient);
ui_draw_vision_maxspeed(s);
ui_draw_vision_speed(s);
ui_draw_vision_event(s);
}
@ -575,7 +551,7 @@ void ui_draw_vision_alert(UIState *s, cereal::ControlsState::AlertSize va_size,
const uint8_t *color = alert_colors[va_color];
int alr_s = alert_size_map[va_size];
const int alr_x = scene->ui_viz_rx- bdr_s;
const int alr_x = scene->ui_viz_rx - bdr_s;
const int alr_w = scene->ui_viz_rw + (bdr_s*2);
const int alr_h = alr_s+(va_size==cereal::ControlsState::AlertSize::NONE?0:bdr_s);
const int alr_y = vwp_h-alr_h;
@ -619,7 +595,7 @@ static void ui_draw_vision(UIState *s) {
glViewport(0, 0, s->fb_w, s->fb_h);
// Draw augmented elements
if (!scene->frontview && !scene->fullview) {
if (!scene->frontview) {
ui_draw_world(s);
}
@ -631,7 +607,6 @@ static void ui_draw_vision(UIState *s) {
}
if (scene->alert_size != cereal::ControlsState::AlertSize::NONE) {
// Controls Alerts
ui_draw_vision_alert(s, scene->alert_size, s->status,
scene->alert_text1.c_str(), scene->alert_text2.c_str());
} else if (!scene->frontview) {
@ -640,22 +615,25 @@ static void ui_draw_vision(UIState *s) {
}
static void ui_draw_background(UIState *s) {
int bg_status = s->status;
assert(bg_status < ARRAYSIZE(bg_colors));
const uint8_t *color = bg_colors[bg_status];
glClearColor(color[0]/256.0, color[1]/256.0, color[2]/256.0, 1.0);
const Color color = bg_colors[s->status];
glClearColor(color.r/256.0, color.g/256.0, color.b/256.0, 1.0);
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
}
void ui_draw(UIState *s) {
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;
ui_draw_background(s);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glViewport(0, 0, s->fb_w, s->fb_h);
nvgBeginFrame(s->vg, s->fb_w, s->fb_h, 1.0f);
ui_draw_sidebar(s);
if (s->started && s->active_app == cereal::UiLayoutState::App::NONE && s->status != STATUS_STOPPED && s->vision_seen) {
if (s->started && s->active_app == cereal::UiLayoutState::App::NONE &&
s->status != STATUS_OFFROAD && s->vision_connected) {
ui_draw_vision(s);
}
nvgEndFrame(s->vg);
@ -820,7 +798,7 @@ void ui_nvg_init(UIState *s) {
{ 1.0, -1.0, x1, y1}, //br
};
glGenVertexArrays(1,&s->frame_vao[i]);
glGenVertexArrays(1, &s->frame_vao[i]);
glBindVertexArray(s->frame_vao[i]);
glGenBuffers(1, &s->frame_vbo[i]);
glBindBuffer(GL_ARRAY_BUFFER, s->frame_vbo[i]);
@ -841,10 +819,8 @@ void ui_nvg_init(UIState *s) {
s->front_frame_mat = matmul(device_transform, full_to_wide_frame_transform);
s->rear_frame_mat = matmul(device_transform, frame_transform);
for(int i = 0;i < UI_BUF_COUNT; i++) {
for(int i = 0; i < UI_BUF_COUNT; i++) {
s->khr[i] = 0;
s->priv_hnds[i] = NULL;
s->khr_front[i] = 0;
s->priv_hnds_front[i] = NULL;
}
}

@ -49,7 +49,6 @@ void MainWindow::closeSettings(){
}
GLWindow::GLWindow(QWidget *parent) : QOpenGLWidget(parent) {
timer = new QTimer(this);
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(timerUpdate()));
@ -72,24 +71,11 @@ void GLWindow::initializeGL() {
ui_state->fb_w = vwp_w;
ui_state->fb_h = vwp_h;
int err = pthread_create(&connect_thread_handle, NULL,
vision_connect_thread, ui_state);
assert(err == 0);
timer->start(50);
}
void GLWindow::timerUpdate(){
pthread_mutex_lock(&ui_state->lock);
ui_update_sizes(ui_state);
check_messages(ui_state);
if (ui_state->vision_connected){
ui_update(ui_state);
}
pthread_mutex_unlock(&ui_state->lock);
update();
}
@ -98,9 +84,7 @@ void GLWindow::resizeGL(int w, int h) {
}
void GLWindow::paintGL() {
pthread_mutex_lock(&ui_state->lock);
ui_draw(ui_state);
pthread_mutex_unlock(&ui_state->lock);
}
void GLWindow::mousePressEvent(QMouseEvent *e) {
@ -116,7 +100,6 @@ void GLWindow::mousePressEvent(QMouseEvent *e) {
if (ui_state->started && (e->x() >= ui_state->scene.ui_viz_rx - bdr_s)){
ui_state->scene.uilayout_sidebarcollapsed = !ui_state->scene.uilayout_sidebarcollapsed;
}
}

@ -45,7 +45,6 @@ protected:
private:
QTimer * timer;
UIState * ui_state;
pthread_t connect_thread_handle;
public slots:
void timerUpdate();

@ -159,13 +159,13 @@ static void ui_draw_sidebar_panda_metric(UIState *s) {
}
static void ui_draw_sidebar_connectivity(UIState *s) {
if (s->scene.athenaStatus == NET_DISCONNECTED) {
ui_draw_sidebar_metric(s, NULL, NULL, 1, 180+158, "CONNECT\nOFFLINE");
} else if (s->scene.athenaStatus == NET_CONNECTED) {
ui_draw_sidebar_metric(s, NULL, NULL, 0, 180+158, "CONNECT\nONLINE");
} else {
ui_draw_sidebar_metric(s, NULL, NULL, 2, 180+158, "CONNECT\nERROR");
}
static std::map<NetStatus, std::pair<const char *, int>> connectivity_map = {
{NET_ERROR, {"CONNECT\nERROR", 2}},
{NET_CONNECTED, {"CONNECT\nONLINE", 0}},
{NET_DISCONNECTED, {"CONNECT\nOFFLINE", 1}},
};
auto net_params = connectivity_map[s->scene.athenaStatus];
ui_draw_sidebar_metric(s, NULL, NULL, net_params.second, 180+158, net_params.first);
}
void ui_draw_sidebar(UIState *s) {

@ -1,10 +1,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
#include <poll.h>
#include <sys/mman.h>
#include <czmq.h>
#include "common/util.h"
#include "common/swaglog.h"
@ -15,23 +16,20 @@
extern volatile sig_atomic_t do_exit;
int write_param_float(float param, const char* param_name, bool persistent_param) {
char s[16];
int size = snprintf(s, sizeof(s), "%f", param);
return write_db_value(param_name, s, MIN(size, sizeof(s)), persistent_param);
return write_db_value(param_name, s, size < sizeof(s) ? size : sizeof(s), persistent_param);
}
void ui_init(UIState *s) {
pthread_mutex_init(&s->lock, NULL);
s->sm = new SubMaster({"model", "controlsState", "uiLayoutState", "liveCalibration", "radarState", "thermal",
"health", "carParams", "ubloxGnss", "driverState", "dMonitoringState"
});
"health", "carParams", "ubloxGnss", "driverState", "dMonitoringState"});
s->ipc_fd = -1;
s->scene.satelliteCount = -1;
s->started = false;
s->vision_seen = false;
s->status = STATUS_OFFROAD;
s->scene.satelliteCount = -1;
read_param(&s->is_metric, "IsMetric");
s->fb = framebuffer_init("ui", 0, true, &s->fb_w, &s->fb_h);
assert(s->fb);
@ -39,41 +37,72 @@ void ui_init(UIState *s) {
ui_nvg_init(s);
}
static void ui_init_vision(UIState *s, const VisionStreamBufs back_bufs,
int num_back_fds, const int *back_fds,
const VisionStreamBufs front_bufs, int num_front_fds,
const int *front_fds) {
assert(num_back_fds == UI_BUF_COUNT);
assert(num_front_fds == UI_BUF_COUNT);
static void ui_init_vision(UIState *s) {
// Invisible until we receive a calibration message.
s->scene.world_objects_visible = false;
vipc_bufs_load(s->bufs, &back_bufs, num_back_fds, back_fds);
vipc_bufs_load(s->front_bufs, &front_bufs, num_front_fds, front_fds);
for (int i = 0; i < UI_BUF_COUNT; i++) {
if (s->khr[i] != 0) {
visionimg_destroy_gl(s->khr[i], s->priv_hnds[i]);
glDeleteTextures(1, &s->frame_texs[i]);
}
s->cur_vision_idx = -1;
s->cur_vision_front_idx = -1;
VisionImg img = {
.fd = s->stream.bufs[i].fd,
.format = VISIONIMG_FORMAT_RGB24,
.width = s->stream.bufs_info.width,
.height = s->stream.bufs_info.height,
.stride = s->stream.bufs_info.stride,
.bpp = 3,
.size = s->stream.bufs_info.buf_len,
};
#ifndef QCOM
s->priv_hnds[i] = s->stream.bufs[i].addr;
#endif
s->frame_texs[i] = visionimg_to_gl(&img, &s->khr[i], &s->priv_hnds[i]);
s->scene.frontview = getenv("FRONTVIEW") != NULL;
s->scene.fullview = getenv("FULLVIEW") != NULL;
s->scene.world_objects_visible = false; // Invisible until we receive a calibration message.
glBindTexture(GL_TEXTURE_2D, s->frame_texs[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
s->rgb_width = back_bufs.width;
s->rgb_height = back_bufs.height;
s->rgb_stride = back_bufs.stride;
s->rgb_buf_len = back_bufs.buf_len;
// BGR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
}
assert(glGetError() == GL_NO_ERROR);
}
s->rgb_front_width = front_bufs.width;
s->rgb_front_height = front_bufs.height;
s->rgb_front_stride = front_bufs.stride;
s->rgb_front_buf_len = front_bufs.buf_len;
void ui_update_vision(UIState *s) {
read_param(&s->is_metric, "IsMetric");
read_param(&s->longitudinal_control, "LongitudinalControl");
}
if (!s->vision_connected && s->started) {
const VisionStreamType type = s->scene.frontview ? VISION_STREAM_RGB_FRONT : VISION_STREAM_RGB_BACK;
int err = visionstream_init(&s->stream, type, true, nullptr);
if (err == 0) {
ui_init_vision(s);
s->vision_connected = true;
}
}
if (s->vision_connected) {
if (!s->started) goto destroy;
void update_status(UIState *s, int status) {
if (s->status != status) {
s->status = status;
// poll for a new frame
struct pollfd fds[1] = {{
.fd = s->stream.ipc_fd,
.events = POLLOUT,
}};
int ret = poll(fds, 1, 100);
if (ret > 0) {
if (!visionstream_get(&s->stream, nullptr)) goto destroy;
}
}
return;
destroy:
visionstream_destroy(&s->stream);
s->vision_connected = false;
}
static inline void fill_path_points(const cereal::ModelData::PathData::Reader &path, float *points) {
@ -83,13 +112,21 @@ static inline void fill_path_points(const cereal::ModelData::PathData::Reader &p
}
}
void handle_message(UIState *s, SubMaster &sm) {
void update_sockets(UIState *s) {
UIScene &scene = s->scene;
SubMaster &sm = *(s->sm);
// poll sockets
if (sm.update(0) == 0){
return;
}
if (s->started && sm.updated("controlsState")) {
auto event = sm["controlsState"];
scene.controls_state = event.getControlsState();
s->controls_seen = true;
// TODO: the alert stuff shouldn't be handled here
auto alert_sound = scene.controls_state.getAlertSound();
if (scene.alert_type.compare(scene.controls_state.getAlertType()) != 0) {
if (alert_sound == AudibleAlert::NONE) {
@ -104,11 +141,11 @@ void handle_message(UIState *s, SubMaster &sm) {
scene.alert_type = scene.controls_state.getAlertType();
auto alertStatus = scene.controls_state.getAlertStatus();
if (alertStatus == cereal::ControlsState::AlertStatus::USER_PROMPT) {
update_status(s, STATUS_WARNING);
s->status = STATUS_WARNING;
} else if (alertStatus == cereal::ControlsState::AlertStatus::CRITICAL) {
update_status(s, STATUS_ALERT);
s->status = STATUS_ALERT;
} else{
update_status(s, scene.controls_state.getEnabled() ? STATUS_ENGAGED : STATUS_DISENGAGED);
s->status = scene.controls_state.getEnabled() ? STATUS_ENGAGED : STATUS_DISENGAGED;
}
float alert_blinkingrate = scene.controls_state.getAlertBlinkingRate();
@ -147,16 +184,6 @@ void handle_message(UIState *s, SubMaster &sm) {
fill_path_points(scene.model.getLeftLane(), scene.left_lane_points);
fill_path_points(scene.model.getRightLane(), scene.right_lane_points);
}
// else if (which == cereal::Event::LIVE_MPC) {
// auto data = event.getLiveMpc();
// auto x_list = data.getX();
// auto y_list = data.getY();
// for (int i = 0; i < 50; i++){
// scene.mpc_x[i] = x_list[i];
// scene.mpc_y[i] = y_list[i];
// }
// s->livempc_or_radarstate_changed = true;
// }
if (sm.updated("uiLayoutState")) {
auto data = sm["uiLayoutState"].getUiLayoutState();
s->active_app = data.getActiveApp();
@ -173,6 +200,8 @@ void handle_message(UIState *s, SubMaster &sm) {
}
if (sm.updated("health")) {
scene.hwType = sm["health"].getHealth().getHwType();
} else if ((s->sm->frame - s->sm->rcv_frame("health")) > 5*UI_FREQ) {
scene.hwType = cereal::HealthData::HwType::UNKNOWN;
}
if (sm.updated("carParams")) {
s->longitudinal_control = sm["carParams"].getCarParams().getOpenpilotLongitudinalControl();
@ -184,267 +213,67 @@ void handle_message(UIState *s, SubMaster &sm) {
scene.dmonitoring_state = sm["dMonitoringState"].getDMonitoringState();
scene.is_rhd = scene.dmonitoring_state.getIsRHD();
scene.frontview = scene.dmonitoring_state.getIsPreview();
} else if ((sm.frame - sm.rcv_frame("dMonitoringState")) > 1*UI_FREQ) {
} else if ((sm.frame - sm.rcv_frame("dMonitoringState")) > UI_FREQ/2) {
scene.frontview = false;
}
s->started = scene.thermal.getStarted() || scene.frontview;
// Handle onroad/offroad transition
if (!s->started) {
if (s->status != STATUS_STOPPED) {
update_status(s, STATUS_STOPPED);
s->vision_seen = false;
s->controls_seen = false;
s->active_app = cereal::UiLayoutState::App::HOME;
}
} else if (s->status == STATUS_STOPPED) {
update_status(s, STATUS_DISENGAGED);
s->active_app = cereal::UiLayoutState::App::NONE;
}
}
void check_messages(UIState *s) {
if (s->sm->update(0) > 0){
handle_message(s, *(s->sm));
}
}
void ui_update_sizes(UIState *s){
// 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;
}
void ui_update(UIState *s) {
int err;
if (s->vision_connect_firstrun) {
// cant run this in connector thread because opengl.
// do this here for now in lieu of a run_on_main_thread event
for (int i=0; i<UI_BUF_COUNT; i++) {
if(s->khr[i] != 0) {
visionimg_destroy_gl(s->khr[i], s->priv_hnds[i]);
glDeleteTextures(1, &s->frame_texs[i]);
}
VisionImg img = {
.fd = s->bufs[i].fd,
.format = VISIONIMG_FORMAT_RGB24,
.width = s->rgb_width,
.height = s->rgb_height,
.stride = s->rgb_stride,
.bpp = 3,
.size = s->rgb_buf_len,
};
#ifndef QCOM
s->priv_hnds[i] = s->bufs[i].addr;
#endif
s->frame_texs[i] = visionimg_to_gl(&img, &s->khr[i], &s->priv_hnds[i]);
glBindTexture(GL_TEXTURE_2D, s->frame_texs[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
update_sockets(s);
ui_update_vision(s);
// BGR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
}
for (int i=0; i<UI_BUF_COUNT; i++) {
if(s->khr_front[i] != 0) {
visionimg_destroy_gl(s->khr_front[i], s->priv_hnds_front[i]);
glDeleteTextures(1, &s->frame_front_texs[i]);
}
VisionImg img = {
.fd = s->front_bufs[i].fd,
.format = VISIONIMG_FORMAT_RGB24,
.width = s->rgb_front_width,
.height = s->rgb_front_height,
.stride = s->rgb_front_stride,
.bpp = 3,
.size = s->rgb_front_buf_len,
};
#ifndef QCOM
s->priv_hnds_front[i] = s->bufs[i].addr;
#endif
s->frame_front_texs[i] = visionimg_to_gl(&img, &s->khr_front[i], &s->priv_hnds_front[i]);
glBindTexture(GL_TEXTURE_2D, s->frame_front_texs[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// BGR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
}
assert(glGetError() == GL_NO_ERROR);
// Handle onroad/offroad transition
if (!s->started && s->status != STATUS_OFFROAD) {
s->status = STATUS_OFFROAD;
s->active_app = cereal::UiLayoutState::App::HOME;
s->scene.uilayout_sidebarcollapsed = false;
} else if (s->started && s->status == STATUS_OFFROAD) {
s->status = STATUS_DISENGAGED;
s->started_frame = s->sm->frame;
s->active_app = cereal::UiLayoutState::App::NONE;
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;
s->vision_connect_firstrun = false;
s->alert_blinking_alpha = 1.0;
s->alert_blinked = false;
s->alert_blinking_alpha = 1.0;
s->scene.alert_size = cereal::ControlsState::AlertSize::NONE;
}
zmq_pollitem_t polls[1] = {{0}};
// Take an rgb image from visiond if there is one
assert(s->ipc_fd >= 0);
while(true) {
if (s->ipc_fd < 0) {
// TODO: rethink this, for now it should only trigger on PC
LOGW("vision disconnected by other thread");
s->vision_connected = false;
return;
}
polls[0].fd = s->ipc_fd;
polls[0].events = ZMQ_POLLIN;
#ifdef UI_60FPS
// uses more CPU in both UI and surfaceflinger
// 16% / 21%
int ret = zmq_poll(polls, 1, 1);
#else
// 9% / 13% = a 14% savings
int ret = zmq_poll(polls, 1, 1000);
#endif
if (ret < 0) {
if (errno == EINTR || errno == EAGAIN) continue;
LOGE("poll failed (%d - %d)", ret, errno);
close(s->ipc_fd);
s->ipc_fd = -1;
s->vision_connected = false;
return;
} else if (ret == 0) {
break;
}
// vision ipc event
VisionPacket rp;
err = vipc_recv(s->ipc_fd, &rp);
if (err <= 0) {
LOGW("vision disconnected");
close(s->ipc_fd);
s->ipc_fd = -1;
s->vision_connected = false;
return;
}
if (rp.type == VIPC_STREAM_ACQUIRE) {
bool front = rp.d.stream_acq.type == VISION_STREAM_RGB_FRONT;
int idx = rp.d.stream_acq.idx;
int release_idx;
if (front) {
release_idx = s->cur_vision_front_idx;
// Handle controls timeout
bool controls_timeout = ((s->sm)->frame - (s->sm)->rcv_frame("controlsState")) > 10*UI_FREQ;
if (s->started && !s->scene.frontview && controls_timeout) {
if ((s->sm)->rcv_frame("controlsState") < s->started_frame) {
// car is started, but controlsState hasn't been seen at all
s->scene.alert_text1 = "openpilot Unavailable";
s->scene.alert_text2 = "Waiting for controls to start";
s->scene.alert_size = cereal::ControlsState::AlertSize::MID;
} else {
release_idx = s->cur_vision_idx;
}
if (release_idx >= 0) {
VisionPacket rep = {
.type = VIPC_STREAM_RELEASE,
.d = { .stream_rel = {
.type = rp.d.stream_acq.type,
.idx = release_idx,
}},
};
vipc_send(s->ipc_fd, &rep);
// car is started, but controls is lagging or died
if (s->scene.alert_text2 != "Controls Unresponsive") {
s->sound.play(AudibleAlert::CHIME_WARNING_REPEAT);
LOGE("Controls unresponsive");
}
if (front) {
assert(idx < UI_BUF_COUNT);
s->cur_vision_front_idx = idx;
} else {
assert(idx < UI_BUF_COUNT);
s->cur_vision_idx = idx;
// printf("v %d\n", ((uint8_t*)s->bufs[idx].addr)[0]);
}
} else {
assert(false);
s->scene.alert_text1 = "TAKE CONTROL IMMEDIATELY";
s->scene.alert_text2 = "Controls Unresponsive";
s->scene.alert_size = cereal::ControlsState::AlertSize::FULL;
s->status = STATUS_ALERT;
}
break;
}
}
static int vision_subscribe(int fd, VisionPacket *rp, VisionStreamType type) {
int err;
LOGW("vision_subscribe type:%d", type);
VisionPacket p1 = {
.type = VIPC_STREAM_SUBSCRIBE,
.d = { .stream_sub = { .type = type, .tbuffer = true, }, },
};
err = vipc_send(fd, &p1);
if (err < 0) {
close(fd);
return 0;
}
do {
err = vipc_recv(fd, rp);
if (err <= 0) {
close(fd);
return 0;
}
// release what we aren't ready for yet
if (rp->type == VIPC_STREAM_ACQUIRE) {
VisionPacket rep = {
.type = VIPC_STREAM_RELEASE,
.d = { .stream_rel = {
.type = rp->d.stream_acq.type,
.idx = rp->d.stream_acq.idx,
}},
};
vipc_send(fd, &rep);
// Read params
if ((s->sm)->frame % (5*UI_FREQ) == 0) {
read_param(&s->is_metric, "IsMetric");
} else if ((s->sm)->frame % (6*UI_FREQ) == 0) {
int param_read = read_param(&s->last_athena_ping, "LastAthenaPingTime");
if (param_read != 0) { // Failed to read param
s->scene.athenaStatus = NET_DISCONNECTED;
} else if (nanos_since_boot() - s->last_athena_ping < 70e9) {
s->scene.athenaStatus = NET_CONNECTED;
} else {
s->scene.athenaStatus = NET_ERROR;
}
} while (rp->type != VIPC_STREAM_BUFS || rp->d.stream_bufs.type != type);
return 1;
}
void* vision_connect_thread(void *args) {
set_thread_name("vision_connect");
UIState *s = (UIState*)args;
while (!do_exit) {
usleep(100000);
pthread_mutex_lock(&s->lock);
bool connected = s->vision_connected;
pthread_mutex_unlock(&s->lock);
if (connected) continue;
int fd = vipc_connect();
if (fd < 0) continue;
VisionPacket back_rp, front_rp;
if (!vision_subscribe(fd, &back_rp, VISION_STREAM_RGB_BACK)) continue;
if (!vision_subscribe(fd, &front_rp, VISION_STREAM_RGB_FRONT)) continue;
pthread_mutex_lock(&s->lock);
assert(!s->vision_connected);
s->ipc_fd = fd;
ui_init_vision(s,
back_rp.d.stream_bufs, back_rp.num_fds, back_rp.fds,
front_rp.d.stream_bufs, front_rp.num_fds, front_rp.fds);
s->vision_connected = true;
s->vision_seen = true;
s->vision_connect_firstrun = true;
// Drain sockets
s->sm->drain();
pthread_mutex_unlock(&s->lock);
}
return NULL;
}

@ -11,11 +11,11 @@
#define NANOVG_GLES3_IMPLEMENTATION
#define nvgCreate nvgCreateGLES3
#endif
#include <atomic>
#include <atomic>
#include <map>
#include <string>
#include <sstream>
#include <pthread.h>
#include "nanovg.h"
@ -27,16 +27,6 @@
#include "common/params.h"
#include "sound.hpp"
#define STATUS_STOPPED 0
#define STATUS_DISENGAGED 1
#define STATUS_ENGAGED 2
#define STATUS_WARNING 3
#define STATUS_ALERT 4
#define NET_CONNECTED 0
#define NET_DISCONNECTED 1
#define NET_ERROR 2
#define COLOR_BLACK nvgRGBA(0, 0, 0, 255)
#define COLOR_BLACK_ALPHA(x) nvgRGBA(0, 0, 0, x)
#define COLOR_WHITE nvgRGBA(255, 255, 255, 255)
@ -45,10 +35,6 @@
#define COLOR_RED nvgRGBA(201, 34, 49, 255)
#define COLOR_OCHRE nvgRGBA(218, 111, 37, 255)
#ifndef QCOM
#define UI_60FPS
#endif
#define UI_BUF_COUNT 4
// TODO: Detect dynamically
@ -82,7 +68,7 @@ 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 = 20; // Hz
const int MODEL_PATH_MAX_VERTICES_CNT = 98;
const int MODEL_LANE_PATH_CNT = 2;
@ -90,33 +76,45 @@ const int TRACK_POINTS_MAX_CNT = 50 * 2;
const int SET_SPEED_NA = 255;
const uint8_t bg_colors[][4] = {
[STATUS_STOPPED] = {0x07, 0x23, 0x39, 0xff},
[STATUS_DISENGAGED] = {0x17, 0x33, 0x49, 0xff},
[STATUS_ENGAGED] = {0x17, 0x86, 0x44, 0xff},
[STATUS_WARNING] = {0xDA, 0x6F, 0x25, 0xff},
[STATUS_ALERT] = {0xC9, 0x22, 0x31, 0xff},
typedef struct Color {
uint8_t r, g, b;
} Color;
typedef enum NetStatus {
NET_CONNECTED,
NET_DISCONNECTED,
NET_ERROR,
} NetStatus;
typedef enum UIStatus {
STATUS_OFFROAD,
STATUS_DISENGAGED,
STATUS_ENGAGED,
STATUS_WARNING,
STATUS_ALERT,
} UIStatus;
static std::map<UIStatus, Color> bg_colors = {
{STATUS_OFFROAD, {0x07, 0x23, 0x39}},
{STATUS_DISENGAGED, {0x17, 0x33, 0x49}},
{STATUS_ENGAGED, {0x17, 0x86, 0x44}},
{STATUS_WARNING, {0xDA, 0x6F, 0x25}},
{STATUS_ALERT, {0xC9, 0x22, 0x31}},
};
typedef struct UIScene {
int frontview;
int fullview;
float mpc_x[50];
float mpc_y[50];
bool world_objects_visible;
mat4 extrinsic_matrix; // Last row is 0 so we can use mat4.
float speedlimit;
bool speedlimit_valid;
bool world_objects_visible;
bool is_rhd;
bool frontview;
bool uilayout_sidebarcollapsed;
// responsive layout
int ui_viz_rx;
int ui_viz_rw;
int ui_viz_ro;
int ui_viz_rx, ui_viz_rw, ui_viz_ro;
std::string alert_text1;
std::string alert_text2;
@ -125,7 +123,7 @@ typedef struct UIScene {
cereal::HealthData::HwType hwType;
int satelliteCount;
uint8_t athenaStatus;
NetStatus athenaStatus;
cereal::ThermalData::Reader thermal;
cereal::RadarState::LeadData::Reader lead_data[2];
@ -154,8 +152,6 @@ typedef struct {
typedef struct UIState {
pthread_mutex_t lock;
// framebuffer
FramebufferState *fb;
int fb_w, fb_h;
@ -176,77 +172,48 @@ typedef struct UIState {
int img_battery_charging;
int img_network[6];
// sockets
SubMaster *sm;
Sound sound;
UIStatus status;
UIScene scene;
cereal::UiLayoutState::App active_app;
// vision state
bool vision_connected;
bool vision_connect_firstrun;
int ipc_fd;
VIPCBuf bufs[UI_BUF_COUNT];
VIPCBuf front_bufs[UI_BUF_COUNT];
int cur_vision_idx;
int cur_vision_front_idx;
VisionStream stream;
// graphics
GLuint frame_program;
GLuint frame_texs[UI_BUF_COUNT];
EGLImageKHR khr[UI_BUF_COUNT];
void *priv_hnds[UI_BUF_COUNT];
GLuint frame_front_texs[UI_BUF_COUNT];
EGLImageKHR khr_front[UI_BUF_COUNT];
void *priv_hnds_front[UI_BUF_COUNT];
GLint frame_pos_loc, frame_texcoord_loc;
GLint frame_texture_loc, frame_transform_loc;
GLuint frame_vao[2], frame_vbo[2], frame_ibo[2];
mat4 rear_frame_mat, front_frame_mat;
int rgb_width, rgb_height, rgb_stride;
size_t rgb_buf_len;
int rgb_front_width, rgb_front_height, rgb_front_stride;
size_t rgb_front_buf_len;
UIScene scene;
// device state
bool awake;
int awake_timeout;
bool controls_seen;
std::atomic<float> light_sensor;
uint64_t last_athena_ping;
int status;
bool started;
bool is_metric;
bool longitudinal_control;
bool is_ego_over_limit;
float alert_blinking_alpha;
bool alert_blinked;
bool started;
bool vision_seen;
std::atomic<float> light_sensor;
int touch_fd;
GLuint frame_vao[2], frame_vbo[2], frame_ibo[2];
mat4 rear_frame_mat, front_frame_mat;
uint64_t last_athena_ping;
uint64_t started_frame;
model_path_vertices_data model_path_vertices[MODEL_LANE_PATH_CNT * 2];
bool alert_blinked;
float alert_blinking_alpha;
track_vertices_data track_vertices[2];
Sound sound;
model_path_vertices_data model_path_vertices[MODEL_LANE_PATH_CNT * 2];
} UIState;
void ui_init(UIState *s);
void ui_update(UIState *s);
void ui_update_sizes(UIState *s);
void* vision_connect_thread(void *args);
void check_messages(UIState *s);
void update_status(UIState *s, int status);
int write_param_float(float param, const char* param_name, bool persistent_param = false);
template <class T>

Loading…
Cancel
Save