Add binary to display text (#1301)
* add binary to display text
* fake text needs status too
* Rename to TextWindow
Co-authored-by: Comma Device <device@comma.ai>
old-commit-hash: 202a4c2011
commatwo_master
parent
860930b198
commit
935753357a
5 changed files with 296 additions and 0 deletions
@ -0,0 +1,74 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
import os |
||||||
|
import subprocess |
||||||
|
from common.basedir import BASEDIR |
||||||
|
|
||||||
|
|
||||||
|
class TextWindow(): |
||||||
|
def __init__(self, s): |
||||||
|
try: |
||||||
|
self.text_proc = subprocess.Popen(["./text", s], |
||||||
|
stdin=subprocess.PIPE, |
||||||
|
cwd=os.path.join(BASEDIR, "selfdrive", "ui", "text"), |
||||||
|
close_fds=True) |
||||||
|
except OSError: |
||||||
|
self.text_proc = None |
||||||
|
|
||||||
|
def get_status(self): |
||||||
|
if self.text_proc is not None: |
||||||
|
self.text_proc.poll() |
||||||
|
return s.text_proc.returncode |
||||||
|
|
||||||
|
return None |
||||||
|
|
||||||
|
def __enter__(self): |
||||||
|
return self |
||||||
|
|
||||||
|
def close(self): |
||||||
|
if self.text_proc is not None: |
||||||
|
self.text_proc.terminate() |
||||||
|
self.text_proc = None |
||||||
|
|
||||||
|
def __del__(self): |
||||||
|
self.close() |
||||||
|
|
||||||
|
def __exit__(self, type, value, traceback): |
||||||
|
self.close() |
||||||
|
|
||||||
|
|
||||||
|
class FakeTextWindow(): |
||||||
|
def __init__(self): |
||||||
|
pass |
||||||
|
|
||||||
|
def get_status(self): |
||||||
|
return None |
||||||
|
|
||||||
|
def __enter__(self): |
||||||
|
return self |
||||||
|
|
||||||
|
def update(self, _): |
||||||
|
pass |
||||||
|
|
||||||
|
def __exit__(self, type, value, traceback): |
||||||
|
pass |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
import time |
||||||
|
text = """Traceback (most recent call last): |
||||||
|
File "./controlsd.py", line 608, in <module> |
||||||
|
main() |
||||||
|
File "./controlsd.py", line 604, in main |
||||||
|
controlsd_thread(sm, pm, logcan) |
||||||
|
File "./controlsd.py", line 455, in controlsd_thread |
||||||
|
1/0 |
||||||
|
ZeroDivisionError: division by zero""" |
||||||
|
print(text) |
||||||
|
|
||||||
|
with TextWindow(text) as s: |
||||||
|
for _ in range(100): |
||||||
|
if s.get_status() == 1: |
||||||
|
print("Got exit button") |
||||||
|
break |
||||||
|
time.sleep(0.1) |
||||||
|
print("gone") |
@ -0,0 +1,73 @@ |
|||||||
|
CC = clang
|
||||||
|
CXX = clang++
|
||||||
|
|
||||||
|
PHONELIBS = ../../../phonelibs
|
||||||
|
|
||||||
|
WARN_FLAGS = -Werror=implicit-function-declaration \
|
||||||
|
-Werror=incompatible-pointer-types \
|
||||||
|
-Werror=int-conversion \
|
||||||
|
-Werror=return-type \
|
||||||
|
-Werror=format-extra-args
|
||||||
|
|
||||||
|
CFLAGS = -std=gnu11 -fPIC -O2 $(WARN_FLAGS)
|
||||||
|
CXXFLAGS = -std=c++11 -fPIC -O2 $(WARN_FLAGS)
|
||||||
|
|
||||||
|
NANOVG_FLAGS = -I$(PHONELIBS)/nanovg
|
||||||
|
|
||||||
|
OPENGL_LIBS = -lGLESv3
|
||||||
|
|
||||||
|
FRAMEBUFFER_LIBS = -lutils -lgui -lEGL
|
||||||
|
|
||||||
|
OBJS = text.o \
|
||||||
|
../../common/framebuffer.o \
|
||||||
|
../../../selfdrive/common/touch.o \
|
||||||
|
$(PHONELIBS)/nanovg/nanovg.o \
|
||||||
|
opensans_regular.o \
|
||||||
|
|
||||||
|
DEPS := $(OBJS:.o=.d)
|
||||||
|
|
||||||
|
.PHONY: all |
||||||
|
all: text |
||||||
|
|
||||||
|
text: $(OBJS) |
||||||
|
@echo "[ LINK ] $@"
|
||||||
|
$(CXX) -fPIC -o '$@' $^ \
|
||||||
|
-s \
|
||||||
|
$(FRAMEBUFFER_LIBS) \
|
||||||
|
-L/system/vendor/lib64 \
|
||||||
|
$(OPENGL_LIBS) \
|
||||||
|
-lm -llog
|
||||||
|
|
||||||
|
opensans_regular.o: ../../assets/fonts/opensans_regular.ttf |
||||||
|
@echo "[ bin2o ] $@"
|
||||||
|
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
|
||||||
|
|
||||||
|
%.o: %.c |
||||||
|
mkdir -p $(@D)
|
||||||
|
@echo "[ CC ] $@"
|
||||||
|
$(CC) $(CPPFLAGS) $(CFLAGS) \
|
||||||
|
-I../.. \
|
||||||
|
-I$(PHONELIBS)/android_frameworks_native/include \
|
||||||
|
-I$(PHONELIBS)/android_system_core/include \
|
||||||
|
-I$(PHONELIBS)/android_hardware_libhardware/include \
|
||||||
|
$(NANOVG_FLAGS) \
|
||||||
|
-c -o '$@' '$<'
|
||||||
|
|
||||||
|
%.o: %.cc |
||||||
|
mkdir -p $(@D)
|
||||||
|
@echo "[ CXX ] $@"
|
||||||
|
$(CXX) $(CPPFLAGS) $(CXXFLAGS) \
|
||||||
|
-I../../selfdrive \
|
||||||
|
-I../../ \
|
||||||
|
-I$(PHONELIBS)/android_frameworks_native/include \
|
||||||
|
-I$(PHONELIBS)/android_system_core/include \
|
||||||
|
-I$(PHONELIBS)/android_hardware_libhardware/include \
|
||||||
|
$(NANOVG_FLAGS) \
|
||||||
|
-c -o '$@' '$<'
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: clean |
||||||
|
clean: |
||||||
|
rm -f text $(OBJS) $(DEPS)
|
||||||
|
|
||||||
|
-include $(DEPS) |
@ -0,0 +1,3 @@ |
|||||||
|
version https://git-lfs.github.com/spec/v1 |
||||||
|
oid sha256:be30fb76fbf9a21853c5357757e126210254f46b758ec2fd7438c24604d2bd70 |
||||||
|
size 494112 |
@ -0,0 +1,141 @@ |
|||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <stdbool.h> |
||||||
|
#include <math.h> |
||||||
|
#include <unistd.h> |
||||||
|
#include <assert.h> |
||||||
|
|
||||||
|
#include <GLES3/gl3.h> |
||||||
|
#include <EGL/egl.h> |
||||||
|
#include <EGL/eglext.h> |
||||||
|
|
||||||
|
#include "nanovg.h" |
||||||
|
#define NANOVG_GLES3_IMPLEMENTATION |
||||||
|
#include "nanovg_gl.h" |
||||||
|
#include "nanovg_gl_utils.h" |
||||||
|
|
||||||
|
|
||||||
|
#include "common/framebuffer.h" |
||||||
|
#include "common/touch.h" |
||||||
|
|
||||||
|
|
||||||
|
#define COLOR_WHITE nvgRGBA(255, 255, 255, 255) |
||||||
|
#define MAX_TEXT_SIZE 2048 |
||||||
|
|
||||||
|
extern const unsigned char _binary_opensans_regular_ttf_start[]; |
||||||
|
extern const unsigned char _binary_opensans_regular_ttf_end[]; |
||||||
|
|
||||||
|
static void set_brightness(int brightness) { |
||||||
|
FILE *f = fopen("/sys/class/leds/lcd-backlight/brightness", "wb"); |
||||||
|
if (f != NULL) { |
||||||
|
fprintf(f, "%d", brightness); |
||||||
|
fclose(f); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
int err; |
||||||
|
|
||||||
|
// spinner
|
||||||
|
int fb_w, fb_h; |
||||||
|
FramebufferState *fb = framebuffer_init("text", 0x00001000, false, |
||||||
|
&fb_w, &fb_h); |
||||||
|
assert(fb); |
||||||
|
|
||||||
|
NVGcontext *vg = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES); |
||||||
|
assert(vg); |
||||||
|
|
||||||
|
int font = nvgCreateFontMem(vg, "regular", (unsigned char*)_binary_opensans_regular_ttf_start, _binary_opensans_regular_ttf_end-_binary_opensans_regular_ttf_start, 0); |
||||||
|
assert(font >= 0); |
||||||
|
|
||||||
|
// Awake
|
||||||
|
framebuffer_set_power(fb, HWC_POWER_MODE_NORMAL); |
||||||
|
set_brightness(255); |
||||||
|
|
||||||
|
glClearColor(0.1, 0.1, 0.1, 1.0); |
||||||
|
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); |
||||||
|
glEnable(GL_BLEND); |
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
||||||
|
nvgBeginFrame(vg, fb_w, fb_h, 1.0f); |
||||||
|
|
||||||
|
// background
|
||||||
|
nvgBeginPath(vg); |
||||||
|
NVGpaint bg = nvgLinearGradient(vg, fb_w, 0, fb_w, fb_h, |
||||||
|
nvgRGBA(0, 0, 0, 175), nvgRGBA(0, 0, 0, 255)); |
||||||
|
nvgFillPaint(vg, bg); |
||||||
|
nvgRect(vg, 0, 0, fb_w, fb_h); |
||||||
|
nvgFill(vg); |
||||||
|
|
||||||
|
|
||||||
|
// Text
|
||||||
|
nvgFillColor(vg, COLOR_WHITE); |
||||||
|
nvgFontSize(vg, 75.0f); |
||||||
|
|
||||||
|
if (argc >= 2) { |
||||||
|
float x = 150; |
||||||
|
float y = 150; |
||||||
|
|
||||||
|
// Copy text
|
||||||
|
char * text = malloc(MAX_TEXT_SIZE); |
||||||
|
strncpy(text, argv[1], MAX_TEXT_SIZE); |
||||||
|
|
||||||
|
float lineh; |
||||||
|
nvgTextMetrics(vg, NULL, NULL, &lineh); |
||||||
|
|
||||||
|
// nvgTextBox strips leading whitespace. We have to reimplement
|
||||||
|
char * next = strtok(text, "\n"); |
||||||
|
while (next != NULL){ |
||||||
|
nvgText(vg, x, y, next, NULL); |
||||||
|
y += lineh; |
||||||
|
next = strtok(NULL, "\n"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Button
|
||||||
|
int b_x = 1500; |
||||||
|
int b_y = 800; |
||||||
|
int b_w = 300; |
||||||
|
int b_h = 150; |
||||||
|
|
||||||
|
nvgBeginPath(vg); |
||||||
|
nvgFillColor(vg, nvgRGBA(8, 8, 8, 255)); |
||||||
|
nvgRoundedRect(vg, b_x, b_y, b_w, b_h, 20); |
||||||
|
nvgFill(vg); |
||||||
|
|
||||||
|
nvgFillColor(vg, nvgRGBA(255, 255, 255, 255)); |
||||||
|
nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); |
||||||
|
nvgText(vg, b_x+b_w/2, b_y+b_h/2, "Exit", NULL); |
||||||
|
|
||||||
|
nvgBeginPath(vg); |
||||||
|
nvgStrokeColor(vg, nvgRGBA(255, 255, 255, 50)); |
||||||
|
nvgStrokeWidth(vg, 5); |
||||||
|
nvgRoundedRect(vg, b_x, b_y, b_w, b_h, 20); |
||||||
|
nvgStroke(vg); |
||||||
|
|
||||||
|
// Draw to screen
|
||||||
|
nvgEndFrame(vg); |
||||||
|
framebuffer_swap(fb); |
||||||
|
assert(glGetError() == GL_NO_ERROR); |
||||||
|
|
||||||
|
|
||||||
|
// Wait for button
|
||||||
|
TouchState touch; |
||||||
|
touch_init(&touch); |
||||||
|
|
||||||
|
while (true){ |
||||||
|
int touch_x = -1, touch_y = -1; |
||||||
|
int res = touch_poll(&touch, &touch_x, &touch_y, 0); |
||||||
|
if (res){ |
||||||
|
|
||||||
|
if (touch_x > b_x && touch_x < b_x + b_w){ |
||||||
|
if (touch_y > b_y && touch_y < b_y + b_h){ |
||||||
|
return 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
usleep(1000000 / 60); |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
Loading…
Reference in new issue